Skip to content

refactor(jetbrains): consolidate worktree change summaries into ChangesPanel - #13583

Merged
10 commits merged into
mainfrom
shiny-pebble
Aug 31, 2026
Merged

refactor(jetbrains): consolidate worktree change summaries into ChangesPanel#13583
10 commits merged into
mainfrom
shiny-pebble

Conversation

@kirillk

@kirillk kirillk commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Issue

Fixes #

Context

Agent Manager's worktree rows, session toolbar, and worktree editor header had three overlapping implementations of "changes" presentation (WorktreeStatsView, BranchChangesBadge, and ad hoc diff-opening logic), each with its own comparison semantics: the editor header mixed committed and local changes into one diff and disabled rename detection, so its numbers didn't match the worktree list's totals.

This PR unifies base (committed, merge-base→HEAD) and local (HEAD→working tree) comparisons behind one backend pipeline and one retained Swing component, then polishes the resulting worktree editor header toolbar based on visual review.

Implementation

  • Backend: extracted shared Git comparison logic into backend/diff/GitComparison.kt. KiloWorkspaceRpcApi.branchDiff is now committed-only; added localDiff for the working-tree side. Both feed KiloWorktreeRpcApiImpl.stats()/dirty() so list totals and the editor header always agree.
  • Frontend: consolidated WorktreeStatsView and BranchChangesBadge into ui/ChangesPanel.kt with Compact/Full modes, reused by the Agent Manager worktree list (via a thin ActiveList hit-cell adapter), the session toolbar, and the worktree editor header (WorktreePrHeaderView/PrHeaderView).
  • Diff editors: centralized opening/naming in KiloDiffEditorKind/KiloDiffEditorContent so every surface (badge click, context-menu "Compare to Base", worktree header) produces identical params and reuses the same tab for a given comparison.
  • Merge with main: this branch was rebased against a concurrent Run Configuration feature (WorktreeRunControl, run header slot) landed on main; resolved by keeping both the new ChangesPanel-based header and the Run control button, and fixing a test that asserted the old text-only Terminal button.
  • UI polish (from interactive review, see screenshots): removed the redundant "Uncommitted"/"vs <base>" text captions from the full header (the tooltip already carries that context); fixed Open/Build-Run vs. Terminal button-size inconsistency — HoverIcon's icon-only path used a fixed 24px square while labelled buttons went through DarculaButtonUI's LAF sizing, so they never matched; added an opt-in HoverIcon.match mode that squares an icon-only button to the LAF-computed labelled-button height instead of a hardcoded constant (verified this needed to come from the LAF, not a fixed token, because the height differs between Darcula and the plain test LAF); added then removed a leading toolbar separator per follow-up feedback, replacing it with a plain left inset on the toolbar row.

Screenshots / Video

No exported before/after image assets from this session — the header changes were iterated live against screenshots pasted directly into chat by the reviewer (captions removed, button paddings equalized, separator placement adjusted), each confirmed before proceeding to the next tweak. See the "How to Test" steps below to reproduce the current state.

How to Test

Manual/local verification

  • Ran ./gradlew typecheck and ./gradlew test from packages/kilo-jetbrains/ after every commit in this branch; latest run: 3400+ frontend/backend tests green, zero failures.
  • Confirmed no lingering references to the removed WorktreeStatsView/BranchChangesBadge classes (grep -rl across packages/kilo-jetbrains).
  • Diffed HoverIcon.kt's labelled-button path against the pre-change baseline to confirm Open/Build-Run sizing is byte-identical to before (only the icon-only Terminal path changed).

Reviewer test steps

  1. Open a worktree with a PR, committed changes, and uncommitted local edits in the Agent Manager.
  2. In the worktree list row, confirm the compact summary shows only base file count + diff stats (no local/ahead/behind), and clicking it opens Changes vs base branch (<branch>).
  3. Open the worktree's session editor tab. In the header, confirm: no "Uncommitted"/"vs <base>" text labels (just counts + tooltips), a separator only appears between the changes summary and the action buttons when both sides have content, and Build/Run, Open, and the icon-only Terminal button are the same height with matching padding.
  4. Click the local (uncommitted) and base groups independently and confirm they open separate, correctly titled/paned diff tabs that don't clobber each other on refresh.

Blocked checks and substitute verification

  • ./gradlew :shared:detekt :backend:detekt :frontend:detekt fails, but with the same weighted-issue counts on main before this branch's changes (confirmed via git stash + rerun) and none of the flagged files are touched by this diff — pre-existing baseline noise, not a regression.

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

… on worktree rows

Agent Manager worktree rows showed no +/- badge for branches that were
fully pushed, because stats() diffed against the worktree's own
@{upstream} instead of the repo's base branch. Once a branch is pushed,
merge-base(HEAD, upstream) equals HEAD, so the diff reported nothing.

stats() now resolves the base branch the same way the branch-diff editor
does (origin/HEAD, then origin/main/master, then local main/master,
falling back to the main worktree's branch), diffs committed work only
(trailing HEAD on the numstat call excludes the working tree), and
reports which base ref it used.

Uncommitted work moves to a new dirty() RPC and gets its own muted badge
next to the PR diff, since it has a different baseline (HEAD) and
refresh cadence than the PR-parity number.
Keep PR badges beside the diff statistics while exposing generic clickable badge slots and model-based action dispatch. Let Agent Manager own PR semantics instead of the shared list and metrics components.
Unify base and local Git comparisons behind shared backend/frontend
boundaries instead of overlapping ad-hoc implementations:

- Extract reusable comparison logic into backend/diff/GitComparison.kt
  and add a committed-only branchDiff plus a new localDiff endpoint.
- Consolidate WorktreeStatsView and BranchChangesBadge into a single
  ChangesPanel with Compact/Full modes, reused across the Agent
  Manager worktree list, session toolbar, and worktree editor header.
- Centralize diff editor opening/naming in KiloDiffEditorKind/Content
  so every surface produces identical params for the same comparison.
- Migrate AgentManagerPanel, ActiveListRenderer, BranchDock,
  WorktreePrHeaderView, and WorktreeSessionEditorPanel onto the new
  component and RPC surface, removing redundant presentation code.

Consolidates the three prior changesets covering PR badge placement,
worktree PR diff counts, and the uncommitted changes badge into one
release note.
# Conflicts:
#	packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/agentManager/worktree/WorktreePrHeaderView.kt
#	packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/agentManager/worktree/WorktreeSessionEditorPanel.kt
#	packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/SessionUi.kt
#	packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/agentManager/worktree/WorktreePrHeaderViewTest.kt
Remove the "Uncommitted" and "vs <base>" text labels from the worktree
session editor header's full ChangesPanel groups, leaving only the file
count and +/- badges. The distinguishing context is still available via
each group's tooltip, so the header stays compact without redundant text.
Add a vertical separator between the changes summary and the trailing
action buttons (Run, Open, Terminal) in the worktree editor header,
shown only when both sides have visible content.

Fix HoverIcon's labelled variant (used by the Open and Build/Run
buttons) to size itself from its actual icon+text content instead of
falling through to DarculaButtonUI's default preferred size, which
enforces a 72x24 dialog-button minimum. That minimum was inflating
short labels like "Open" into much wider buttons than the icon-only
Terminal button, which already bypassed it.
Revert the labelled-button sizing change: Build/Run and Open go back to
the platform's preferred size, so their insets match what they were.

Instead give the icon-only Terminal button the labelled buttons' margin
and toolbar insets, plus a new HoverIcon.match mode that squares it to
the height the look-and-feel gives a button. Deriving that height from
the LAF (rather than a fixed token) keeps it level with its labelled
siblings under both Darcula and the plain test LAF.

Add a leading separator to the header toolbar so the cluster reads as
separator, standard padding, changes summary, separator, actions. Both
separators stay hidden until an action exists, and the padding is a Stack
gap rather than a filler so it collapses with the hidden separator --
leaving dock hosts with no trailing actions unchanged.
The separator before the changes summary read as clutter next to the PR
title. Replace it with standard left padding on the toolbar row itself,
which keeps the summary spaced off the title without drawing a rule.

Padding now lives in the row's border instead of a Stack gap so it no
longer depends on a separator being visible to apply.
}

private fun loadDirty() {
val dir = project.basePath ?: return

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.

WARNING: loadDirty() sends the synthetic frontend basePath to the backend

loadStats() and loadPr() resolve project.kiloRoot() inside the coroutine because, in split mode, project.basePath is a JetBrains Client path that does not exist on the host (ProjectRoot documents this). loadDirty() still uses basePath, so backend dirty() hits sync() → missing directory and returns an empty list. Uncommitted header counts stay at 0 in remote/split mode while committed stats still work.

kiloRoot() is suspend, so the fix is to mirror loadStats(): resolve it inside cs.launch, not by substituting on this line.

Tests miss this because fakeRoot(..., project.basePath!!) makes kiloRoot == basePath, and FakeWorktreeRpcApi.dirty() ignores the directory argument.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

val revs = if (to == null) listOf(from) else listOf(from, to)
val opts = listOf(
"--literal-pathspecs", "-c", "core.quotepath=false", "diff", "--relative", "--no-color",
"--no-ext-diff", "--no-textconv", "--find-renames", "--rename-empty",

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.

WARNING: --rename-empty breaks comparisons on common Git versions

Every git diff (base and local, including stats()/dirty()) passes --rename-empty. That option is recent; typical distro and Xcode Git (2.34–2.43) reject unknown options with a non-zero exit. CmdOut.checked() then throws, so badges and diff editors go empty. --find-renames already covers normal rename detection — drop --rename-empty rather than failing all comparisons for empty-file renames.

Suggested change
"--no-ext-diff", "--no-textconv", "--find-renames", "--rename-empty",
"--no-ext-diff", "--no-textconv", "--find-renames",

Reply with @kilocode-bot fix it to have Kilo Code address this issue.

@kilo-code-bot

kilo-code-bot Bot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: 7 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 6
SUGGESTION 1
Issue Details (click to expand)

WARNING

File Line Issue
packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/agentManager/worktree/WorktreeStatusService.kt 100 loadDirty() uses synthetic project.basePath instead of kiloRoot(), so uncommitted counts stay empty in split/remote mode
packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/diff/GitComparison.kt 97 --rename-empty is rejected by common Git versions and fails every comparison
packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/agentManager/worktree/WorktreeSetupScript.kt 52 cmd.exe /s /c strips wrapping quotes, so CMD setup scripts fail on paths with spaces
packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/agentManager/worktree/WorktreeSetupScript.kt 40 Reused setup tabs send() into a live PTY, so a second Run injects into a busy shell
packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/app/KiloWorkspaceService.kt 336 Creating the setup script never refreshes the cache, so Run stays hidden and the action stays on Create
packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/agentManager/AgentManagerPanel.kt 333 Setup runs without copying root .env files, unlike VS Code and unlike the ported template

SUGGESTION

File Line Issue
.changeset/jetbrains-worktree-setup-script.md 5 Changelog says setup actions are in the settings menu; they are only on the worktree row menu
Files Reviewed (59 files)
  • .changeset/jetbrains-worktree-setup-script.md - 1 issue
  • .changeset/jetbrains-worktree-uncommitted-badge.md
  • packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/diff/GitComparison.kt - 1 issue
  • packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/rpc/KiloWorkspaceRpcApiImpl.kt
  • packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/rpc/KiloWorktreeRpcApiImpl.kt
  • packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/rpc/SetupScriptTemplate.kt
  • packages/kilo-jetbrains/backend/src/test/kotlin/ai/kilocode/backend/rpc/BranchDiffTest.kt
  • packages/kilo-jetbrains/backend/src/test/kotlin/ai/kilocode/backend/rpc/BranchLocalDiffTest.kt
  • packages/kilo-jetbrains/backend/src/test/kotlin/ai/kilocode/backend/rpc/KiloWorktreeRpcApiImplTest.kt
  • packages/kilo-jetbrains/backend/src/test/kotlin/ai/kilocode/backend/rpc/SetupScriptResolutionTest.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/actions/OpenConfigActions.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/actions/OpenWorktreeLocalDiffAction.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/actions/RunWorktreeSetupScriptAction.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/agentManager/AgentManagerPanel.kt - 1 issue
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/agentManager/worktree/KiloWorktreeService.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/agentManager/worktree/WorktreePrHeaderView.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/agentManager/worktree/WorktreeSessionEditorPanel.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/agentManager/worktree/WorktreeSetupScript.kt - 2 issues
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/agentManager/worktree/WorktreeStatsView.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/agentManager/worktree/WorktreeStatusBinding.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/agentManager/worktree/WorktreeStatusService.kt - 1 issue
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/app/KiloWorkspaceService.kt - 1 issue
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/diff/DiffFileStatus.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/diff/KiloDiffEditorContent.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/SessionUi.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/ui/header/BranchChangesBadge.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/ui/header/BranchDock.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/ui/header/PrHeaderView.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/ui/ChangesPanel.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/ui/HoverIcon.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/ui/ToolbarButton.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/ui/list/ActiveListActions.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/ui/list/ActiveListModel.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/ui/list/ActiveListRenderer.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/ui/list/ActiveListView.kt
  • packages/kilo-jetbrains/frontend/src/main/resources/kilo.jetbrains.frontend.xml
  • packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle.properties
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/actions/HistorySessionActionsTest.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/actions/KiloRecoveryActionsTest.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/agentManager/AgentManagerPanelTest.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/agentManager/worktree/WorktreePrHeaderViewTest.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/agentManager/worktree/WorktreeSessionEditorPanelTest.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/agentManager/worktree/WorktreeSetupScriptTest.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/agentManager/worktree/WorktreeStatusServiceTest.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/app/KiloWorkspaceServiceTest.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/diff/KiloDiffEditorContentTest.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/diff/KiloInlineDiffStoreTest.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/session/SessionUiLayoutTest.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/session/ui/header/BranchDockTest.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/session/ui/header/PrHeaderViewTest.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/settings/base/SettingsListViewTest.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/testing/FakeWorkspaceRpcApi.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/testing/FakeWorktreeRpcApi.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/ui/ChangesPanelTest.kt
  • packages/kilo-jetbrains/shared/src/main/kotlin/ai/kilocode/rpc/KiloWorkspaceRpcApi.kt
  • packages/kilo-jetbrains/shared/src/main/kotlin/ai/kilocode/rpc/KiloWorktreeRpcApi.kt
  • packages/kilo-jetbrains/shared/src/main/kotlin/ai/kilocode/rpc/dto/SetupScriptTargetDto.kt
  • packages/kilo-jetbrains/shared/src/main/kotlin/ai/kilocode/rpc/dto/WorktreeDto.kt

Fix these issues in Kilo Cloud

Previous Review Summary (commit e0be1a7)

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

Previous review (commit e0be1a7)

Status: 2 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 2
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/agentManager/worktree/WorktreeStatusService.kt 100 loadDirty() uses synthetic project.basePath instead of kiloRoot(), so uncommitted counts stay empty in split/remote mode
packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/diff/GitComparison.kt 97 --rename-empty is rejected by common Git versions and fails every comparison
Files Reviewed (47 files)
  • .changeset/jetbrains-worktree-uncommitted-badge.md
  • packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/diff/GitComparison.kt - 1 issue
  • packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/rpc/KiloWorkspaceRpcApiImpl.kt
  • packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/rpc/KiloWorktreeRpcApiImpl.kt
  • packages/kilo-jetbrains/backend/src/test/kotlin/ai/kilocode/backend/rpc/BranchDiffTest.kt
  • packages/kilo-jetbrains/backend/src/test/kotlin/ai/kilocode/backend/rpc/BranchLocalDiffTest.kt
  • packages/kilo-jetbrains/backend/src/test/kotlin/ai/kilocode/backend/rpc/KiloWorktreeRpcApiImplTest.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/agentManager/AgentManagerPanel.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/agentManager/worktree/KiloWorktreeService.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/agentManager/worktree/WorktreePrHeaderView.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/agentManager/worktree/WorktreeSessionEditorPanel.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/agentManager/worktree/WorktreeStatsView.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/agentManager/worktree/WorktreeStatusBinding.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/agentManager/worktree/WorktreeStatusService.kt - 1 issue
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/app/KiloWorkspaceService.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/diff/DiffFileStatus.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/diff/KiloDiffEditorContent.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/SessionUi.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/ui/header/BranchChangesBadge.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/ui/header/BranchDock.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/ui/header/PrHeaderView.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/ui/ChangesPanel.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/ui/HoverIcon.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/ui/ToolbarButton.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/ui/list/ActiveListActions.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/ui/list/ActiveListModel.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/ui/list/ActiveListRenderer.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/ui/list/ActiveListView.kt
  • packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle.properties
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/agentManager/AgentManagerPanelTest.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/agentManager/worktree/WorktreePrHeaderViewTest.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/agentManager/worktree/WorktreeSessionEditorPanelTest.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/agentManager/worktree/WorktreeStatusServiceTest.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/app/KiloWorkspaceServiceTest.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/diff/KiloDiffEditorContentTest.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/diff/KiloInlineDiffStoreTest.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/session/SessionUiLayoutTest.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/session/ui/header/BranchDockTest.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/session/ui/header/PrHeaderViewTest.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/settings/base/SettingsListViewTest.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/testing/FakeWorkspaceRpcApi.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/testing/FakeWorktreeRpcApi.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/ui/ChangesPanelTest.kt
  • packages/kilo-jetbrains/shared/src/main/kotlin/ai/kilocode/rpc/KiloWorkspaceRpcApi.kt
  • packages/kilo-jetbrains/shared/src/main/kotlin/ai/kilocode/rpc/KiloWorktreeRpcApi.kt
  • packages/kilo-jetbrains/shared/src/main/kotlin/ai/kilocode/rpc/dto/WorktreeDto.kt

Fix these issues in Kilo Cloud


Reviewed by grok-4.6 · Input: 249.3K · Output: 30.1K · Cached: 1M

Review guidance: REVIEW.md from base branch main

Port VS Code's worktree setup script (.kilo/setup-script[.sh|.ps1|.cmd|
.bat]) to the JetBrains plugin:

- Resolve the script per-platform with disjoint POSIX/Windows candidate
  lists, and create it from VS Code's own templates when opened and
  missing (backend/rpc/SetupScriptTemplate.kt).
- Run it in a terminal tab dedicated to the worktree (distinct from the
  Terminal button's tab), with WORKTREE_PATH/REPO_PATH set via
  envVariables() so the sent command needs no shell-specific env-prefix
  syntax.
- Fire automatically, non-blocking, when a worktree is created (covers
  create, import, and move-to-worktree); silent no-op when no script
  exists.
- Add Open/Create + Run to the worktree row menu (hidden on the main
  row); Open/Create only, not Run, in the tool-window settings popup.

Also shorten several worktree row action labels and add "Open
Uncommitted Changes" (KiloDiffComparison.LOCAL) alongside the existing
base-diff action:

- Open Pull Request in Browser -> Open in Browser
- Open Diff Against Base Branch -> Open Diff Against Base
- Open/Run Worktree Setup Script -> Open/Run Worktree Setup
- Delete Worktree -> Delete
internal fun setupScriptCommand(script: SetupScriptTargetDto): String = when (script.kind) {
SetupScriptKind.POSIX -> "sh ${quotePosix(script.path)}"
SetupScriptKind.POWERSHELL -> "powershell.exe -NoLogo -NoProfile -ExecutionPolicy Bypass -File ${quoteWindows(script.path)}"
SetupScriptKind.CMD -> "cmd.exe /d /s /c ${quoteWindows(script.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.

WARNING: cmd.exe /s /c strips the wrapping quotes, so paths with spaces break

/s makes cmd drop the first and last quote of the /c remainder. cmd.exe /d /s /c "C:\\Users\\Jane Doe\\repo\\.kilo\\setup-script.cmd" therefore becomes the unquoted command C:\Users\Jane Doe\repo\.kilo\setup-script.cmd, which cmd splits on spaces. VS Code avoids this by spawning argv; here the string is typed into a shell. Extra quotes after /c (""path"") are the usual /s fix so one quoted pair remains after the strip.

Suggested change
SetupScriptKind.CMD -> "cmd.exe /d /s /c ${quoteWindows(script.path)}"
SetupScriptKind.CMD -> "cmd.exe /d /s /c \"${quoteWindows(script.path)}\""

Reply with @kilocode-bot fix it to have Kilo Code address this issue.

existing.content.manager?.setSelectedContent(existing.content, true)
}
ToolWindowManager.getInstance(project).getToolWindow(TerminalToolWindowFactory.TOOL_WINDOW_ID)?.activate(null)
tab.view.createSendTextBuilder().shouldExecute().send(setupScriptCommand(script))

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.

WARNING: Reused setup tabs still send() the command into a live PTY

openTerminal() reuses a tagged tab and returns without typing. This path reuses the dedicated setup tab, then always shouldExecute().send(...). A second Run, or Run while auto-run is still going, dumps the command into a busy shell (stdin of npm install, a pager, a partial line). workingDirectory / envVariables are applied only at tab creation, so a reused tab the user cd'd away from also runs in the wrong directory. Create a new tab (as GhAuth does) or focus-and-return when the tagged tab already exists.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

fun openSetupScript(directory: String, done: (Boolean) -> Unit) {
cs.launch {
val ok = try {
call { this.openSetupScript(directory) }

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.

WARNING: Creating the setup script never updates the setupScript cache

OpenSetupScriptAction and canRunSetup only call refreshSetupScriptTarget when the map entry is missing. After the first lookup stores exists = false, openSetupScript writes the file but leaves the cache stale. The row menu then stays on "Create Worktree Setup" and canRunSetup keeps Run hidden until restart. On success, refresh the cache (or always re-fetch on menu update, like workspace() does for local/global config).


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

val target = project ?: return
service<KiloWorkspaceService>().ifSetupScriptExists(controller.directory) { script ->
Telemetry.send("Worktree Setup Script Run", mapOf("surface" to "auto"))
runWorktreeSetupScript(target, script, created.path, controller.directory)

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.

WARNING: Setup runs without copying root .env files, unlike VS Code

VS Code runSetupScriptForWorktree always copyEnvFiles from the main repo into the worktree before invoking the script. The ported template (SetupScriptTemplate) tells users that copy already happened and that the script should not redo root .env. JetBrains git worktree add does not copy gitignored env files, and neither auto-run nor runSetup does either. Scripts written against that template (or shared with VS Code) will not see .env in the worktree. This needs a host-side copy (backend RPC in split mode) before both auto and manual runs.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

"@kilocode/kilo-jetbrains": minor
---

Run the worktree setup script (`.kilo/setup-script`) in a terminal when a new worktree is created, and add actions to open, create, or run it from the worktree row menu and the settings menu.

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.

SUGGESTION: Release note mentions a settings-menu action that is not wired

Kilo.OpenSetupScript / Kilo.Worktree.RunSetupScript are only in Kilo.Worktree.RowMenu. Tests assert Kilo.OpenSetupScript is not in Kilo.SettingsGroup. Users reading the changelog will look in the wrong menu.

Suggested change
Run the worktree setup script (`.kilo/setup-script`) in a terminal when a new worktree is created, and add actions to open, create, or run it from the worktree row menu and the settings menu.
Run the worktree setup script (`.kilo/setup-script`) in a terminal when a new worktree is created, and add actions to open, create, or run it from the worktree row menu.

Reply with @kilocode-bot fix it to have Kilo Code address this issue.

@kirillk kirillk closed this pull request by merging all changes into main in ab14325 Aug 31, 2026
@kirillk
kirillk deleted the shiny-pebble branch August 31, 2026 12:42
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.

1 participant