* feat(vscode): add foundational types and abstractions for unified diff panel
Introduce the core type definitions and abstractions that support the
upcoming session diff viewer:
- PanelSurface: testable abstraction over vscode.WebviewPanel
- DiffSource/DiffSourceDescriptor: contracts for swappable diff providers
- DiffSourceCatalog: stub registry for enumerating and constructing sources
- PanelContext/DiffFile: cross-cutting types shared by manager and webview
* feat(diff): implement worktree diff source with polling and file revert
Add WorktreeDiffSource, a DiffSource implementation that computes diffs
between the local working tree and the base branch. Key behaviors:
- Resolves the diff target from the workspace root via GitOps
- Performs an initial fetch then polls every 2.5s with hash-based dedup
- Supports single-file revert through WorktreeDiffClient
- Posts structured messages (loading, diffs) to the panel via DiffSourcePost
* add(vscode): session diff source and unified patch parser
Introduce two new modules under the diff sources layer:
- patch-to-before-after.ts: reconstructs before/after file content
from full-context unified diff patches by filtering line prefixes
- session.ts: SessionDiffSource fetches accumulated diffs for a given
session, converts patches to before/after pairs, and posts results
to the diff panel without polling or SSE
* feat(diff): wire up diff source catalog with session and worktree builders
Replace stub implementations in DiffSourceCatalog with real logic:
- Inject KiloConnectionService and use it to fetch session diffs
- Populate listAvailable based on PanelContext (workspace root, session)
- Route build() to WorktreeDiffSource or SessionDiffSource by id prefix
- Extract sessionDescriptor() and SESSION_PREFIX from SessionDiffSource
to decouple descriptor creation from class instantiation
- Export WORKSPACE_DESCRIPTOR from worktree module for catalog reuse
* refactor(vscode): introduce DiffPanelManager and centralize diff panel lifecycle
Extract panel ownership out of DiffViewerProvider into a new
DiffPanelManager class that manages a single global "Changes" webview.
Key changes:
- Add DiffPanelManager with source-swapping, loading pulse, webview
serialization, and disposable lifecycle management
- Add testable Scheduler abstraction to decouple setTimeout usage
- Extend DiffSourceCatalog with defaultSourceId() resolution logic
and replace magic "workspace" string with WORKSPACE_SOURCE_ID const
- Extract sessionSourceId() helper in session source module
- Thread sessionId through openChanges command and sidebar context so
the panel can open directly to the relevant session diff
- Re-register webview panel serializer under DiffPanelManager.viewType
* feat(diff): add source descriptor and capability message types for webview
Introduce new extension-to-webview and webview-to-extension message
interfaces to support multi-source diff panel switching:
- DiffSourceCapabilities, DiffSourceDescriptor for describing available
diff sources with revert/comments flags and grouping metadata
- SetAvailableSourcesMessage and DiffViewerCapabilitiesMessage for
pushing source lists and active capabilities to the webview
- SelectSourceRequest for the webview to request a source switch
* refactor(webview): integrate diff source picker into viewer and relocate shared types
Move DiffSourceCapabilities and DiffSourceDescriptor interfaces out of
extension-messages.ts into the shared diff/sources/types module, and
re-export them via import. Add DiffPickerHeader component with a
grouped Select dropdown for switching between multiple diff sources.
Wire source selection state and capability tracking into DiffViewerApp,
handling setAvailableSources and diffViewer.capabilities messages and
conditionally rendering the picker header above the diff view.
* feat(diff-viewer): add canRevert and canComment capability flags to full-screen diff
Introduce two optional boolean props (`canRevert`, `canComment`) on
FullScreenDiffView that allow callers to disable revert actions and
comment creation based on the active diff source's capabilities.
Guard gutter click handlers, keyboard shortcuts, the "Send all" button,
revert buttons, and sidebar revert callbacks behind these flags. In
DiffViewerApp, forward the capability values from the selected source
and reset transient UI state (comments, diff style, reverting set) on
source switches via a reactive effect.
* test(vscode): add unit tests for diff panel manager, source catalog, and patch utilities
Cover DiffPanelManager lifecycle (open, reveal, dispose, deserialized
panel disposal, source switching, comment forwarding), DiffSourceCatalog
listing/defaulting/building logic, SessionDiffSource fetch-and-convert
flow, and patchToBeforeAfter edge cases.
Also refactor DiffPanelManager to decouple panel creation from surface
adoption: the createSurface factory no longer receives a panel argument,
panel construction moves into a private defaultCreateSurface method, and
deserializePanel now disposes stale panels instead of rewiring them.
Extend the vscode mock with a createOutputChannel stub to support the
new test harness.
* refactor(diff): extract command-context assembly into DiffPanelManager.openFromCommand
Move PanelContext construction (workspace root resolution, session ID
lookup, initial source selection) out of the extension command handler
and into a dedicated openFromCommand method on DiffPanelManager. This
eliminates the extension's direct dependency on getWorkspaceRoot and
provider.getCurrentSessionId by accepting a sessionIdProvider callback
through DiffPanelManagerOptions.
Update tests to cover both provider-based and arg-based session ID
resolution paths in openFromCommand.
* feat(vscode): unify changes panel with multi-source diff architecture
Delete the legacy DiffViewerProvider in favor of the new
DiffPanelManager-based architecture. Decompose review-utils into
focused modules under diff/shared/ (client, hash, target) and update
all consumers to import from the new locations.
- Remove DiffViewerProvider and its registration in extension.ts
- Extract WorktreeDiffClient, DiffTarget into diff/shared/client
- Extract hashFileDiffs into diff/shared/hash
- Extract resolveLocalDiffTarget into diff/shared/target
- Slim down review-utils to only VS Code UI helpers
- Add changeset for the unified Changes panel feature
BREAKING CHANGE: DiffViewerProvider is removed; all diff viewing now routes through DiffPanelManager
* refactor(diff): add polling with hash dedup to SessionDiffSource
Upgrade SessionDiffSource from one-shot fetch to periodic polling
(2.5s interval) with hash-based deduplication, matching the pattern
already used by WorktreeDiffSource. Also clean up legacy references
in WorktreeDiffSource doc comments.
- Introduce POLL_INTERVAL_MS constant and start/stop polling lifecycle
- Track lastHash to skip redundant diff posts when content unchanged
- Extract fetchDiffs helper to share between initialFetch and poll
- Guard all post calls against disposed state
- Add comprehensive polling unit tests with scripted fetch helper
* fix(ui): rename worktreeStats() calls to session.summary() in ChatView
Update ChatView component to use the renamed `session.summary()`
accessor instead of the deprecated `session.worktreeStats()` method,
aligning with the unified multi-source diff architecture.
* feat(diff): add snapshots-disabled notice to session diff source
Introduce a `notice` message type in the diff source protocol so that
`SessionDiffSource` can warn users when snapshot tracking is turned off
for their repository. The check queries the workspace config before
fetching diffs; when disabled, polling is skipped entirely and a
warning banner is rendered in the diff viewer webview.
- Add `SnapshotEnabledCheck` callback wired through `DiffSourceCatalog`
- Extend `DiffSourceMessage` and `ExtensionMessage` with `notice` type
- Forward notice messages from `DiffPanelManager` to the webview
- Render warning banner with icon in `DiffViewerApp`
- Add CSS for `.diff-viewer-notice` component
- Cover new behavior with unit tests
* refactor(i18n): replace hardcoded notice strings with typed keys and localized messages
Convert the diff viewer notice system from passing raw English strings
through the message protocol to using well-known typed identifiers that
the webview resolves to translated text at render time.
- Define `DiffSourceNotice` union type in source protocol layer
- Define `DiffViewerNotice` union type in webview message contract
- Change `notice` field from `message: string` to `notice: T | undefined`
- Map notice identifiers to i18n keys in `DiffViewerApp` via lookup table
- Localize `DiffPickerHeader` labels and group names through `useLanguage`
- Add `diffViewer.*` translation keys across all 19 locale files
- Update unit tests to assert typed notice identifiers
* docs(changeset): update unified diff panel description
Clarify feature summary to mention sidebar badge counts and
snapshots-disabled warning alongside the source dropdown.
* feat(vscode): port markdown diff render ahead of main merge
Cherry-picks the user-facing bits of main's #9846 (render markdown diffs) into
this branch so merging main later is trivial for the 5 shared files. Wires the
markdown toggle through the new DiffPanelManager architecture as global state,
persisted via the kilo-code.new.diff.renderMarkdown setting.
* refactor(vscode): replace if-chain message dispatch with handler map
Extract DiffPanelManager.onMessage logic into a declarative
messageHandlers record and a dedicated onWebviewReady method.
Also fix import paths for DiffSourceDescriptor/DiffSourceCapabilities
to reference canonical source types, add explicit generic to Set<string>,
and extend webview tsconfig include to cover diff-viewer and diff-virtual.
* style(ui): add padding to select section headers
* fix: formatting
* fix(vscode): prevent stale source activation after panel teardown
Introduce an epoch counter to guard against race conditions where
activateSource completes its async initialFetch after the panel has
been disposed or the source has been swapped. The epoch is incremented
on every source teardown and checked before starting polling.
* refactor(vscode): scope source post guard to lifecycle epoch
Pass the epoch counter into createSourcePost so that messages emitted
by a source after its lifecycle has ended are silently dropped. This
closes a gap where polling callbacks could still push updates to the
surface after the source was swapped out.
* feat(diff-viewer): rename workspace source to "Local Changes" and add tooltip
Remove the "Workspace" source group, moving the worktree source under
"Git". Rename its label from "Workspace local" to "Local Changes" across
all locales and introduce a tooltip explaining that it covers all branch
changes vs the base (uncommitted files and local commits). The picker
header now renders option tooltips on hover with a delayed open.
* docs(i18n): translate workspace tooltip into all supported locales
Replace the English fallback string for
`diffViewer.source.workspace.tooltip` with native translations in ar,
bs, ja, ko, no, pl, ru, th, tr, uk, zh, and zht locale files.
* style(diff-viewer): rename parameter `d` to `desc` in DiffPickerHeader
Improve readability by expanding the terse single-letter parameter name
to a more descriptive `desc` across helper functions and the render
callback in DiffPickerHeader.
* refactor(diff-sources): replace hardcoded label with type-driven i18n key lookup
Replace the `label` string field in DiffSourceDescriptor with a
`DiffSourceType` discriminant (`"workspace" | "session"`). The webview
now composes i18n keys dynamically from the type, eliminating ad-hoc
id-matching logic in DiffPickerHeader and ensuring every source gets
both a label and a tooltip via the translation dictionaries.
Also adds `diffViewer.source.session.tooltip` translations for all
supported locales and introduces descriptor-type stability tests.
* fix(i18n): shorten session source label by removing "current" qualifier across all locales
* refactor(diff): extract shared polling interval constant into dedicated module
Consolidate the duplicated `POLL_INTERVAL_MS` definitions from
`session.ts`, `worktree.ts`, and the hardcoded literal in
`worktree-diff-controller.ts` into a single `DIFF_POLL_INTERVAL_MS`
export in `diff/polling.ts`. Update all consumers and tests to
reference the new canonical constant.
* feat(diff): replace DiffPanelManager with DiffViewerProvider and SourceController
Remove the `manager/` directory (DiffPanelManager, panel-surface,
scheduler) and introduce two focused replacements:
- `DiffViewerProvider`: owns the webview panel lifecycle, HTML rendering,
and message routing directly against `vscode.WebviewPanel`
- `SourceController`: manages the active DiffSource with epoch-based
stale-message filtering, decoupled from any webview abstraction
The PanelSurface and Scheduler indirection layers are eliminated in
favor of direct VS Code API usage in the provider and a simpler
epoch-guarded post function in the controller. Tests are rewritten
to exercise SourceController in isolation without fake surfaces.
BREAKING CHANGE: DiffPanelManager, PanelSurface, and Scheduler exports are removed
* refactor(diff): decouple SourceController from DiffSourceCatalog via dependency injection
Replace the direct DiffSourceCatalog dependency in SourceController with
two injected function callbacks (`build` and `listAvailable`), removing
the tight coupling to the catalog class. DiffViewerProvider now passes
thin wrappers that delegate to the catalog instance.
Update tests to use lightweight inline fakes instead of the FakeCatalog
subclass, and remove redundant polling/lifecycle tests that tested
implementation details rather than behavior.
* feat(diff): add lazy per-file content loading for worktree diffs
Introduce on-demand fetching of full file content (before/after) for
summarized diff entries. The worktree source now polls only a lightweight
summary and resolves detail via `requestFile` when the webview expands a
file.
- Add `requestFile` to `DiffSource` interface and implement in
`WorktreeDiffSource` using local git operations
- Wire `diffViewer.requestFile` message through DiffViewerProvider to
SourceController
- Add `diffViewer.diffFile` extension message to deliver single-file
detail back to the webview
- Webview merges incoming summaries with cached detail, tracks
per-file loading state, and auto-refreshes stale entries
* refactor(session): replace custom patch parser with shared kilo-ui session-diff utilities
Remove the hand-rolled `patchToBeforeAfter` function and its unit tests
in favor of the `normalize` and `text` helpers exported from
`@kilocode/kilo-ui/session-diff`. This eliminates duplicated parsing
logic and aligns the extension with the canonical diff reconstruction
used across the UI layer.
* test(diff): add hash utility tests and remove obsolete polling specs
Introduce a dedicated test suite for `hashFileDiffs` covering stability,
field sensitivity, and summarized-patch exclusion semantics. Remove the
now-unused polling tests and their helper functions (`scripted`, `wait`,
`modifiedPatchV2`) from the session source spec, reducing test surface
to match the current implementation boundaries.
* style(webview): add spacing for diff picker header component
* fix(diff): prefer workspace over session as default diff source
Change priority order in defaultSourceId so workspace source takes
precedence over session source when both workspaceRoot and sessionId
are present. Update ChatView to use renamed worktreeStats() accessor.
* fix(vscode): correct DiffViewerProvider path, bump max-lines cap, and apply font-size token
Update font-size arch test to reflect DiffViewerProvider's move into
src/diff/, raise KiloProvider max-lines eslint cap to 3500, and
replace hardcoded 12px in banners.css with --kilo-font-size-12.
Remove the `.kilo-diff-theme` utility class and its dedicated stylesheet,
relocating all Pierre diff engine custom properties into the centralized
`vscode-bridge.css` theme definition. This allows diff components to
inherit theming from the document root without requiring an explicit
class annotation on each container element.
- Delete `webview-ui/src/styles/diff.css`
- Drop `kilo-diff-theme` class from DiffPanel, FullScreenDiffView,
DiffVirtualApp, and PermissionDiff components
- Remove corresponding `@import` statements from chat.css and
agent-manager.css
Hardcodes the list of active and disabled workflows and fails CI when
.github/workflows/ drifts. Wired into check-opencode-annotations so we
don't add a new workflow file for this.