From 048338a31422fd057bcaefc8db6c397cf33adff1 Mon Sep 17 00:00:00 2001 From: marius-kilocode Date: Thu, 21 May 2026 11:37:59 +0200 Subject: [PATCH] fix(vscode): clear stale diff preview loading --- .changeset/clear-diffs-settle.md | 5 +++ .../kilo-vscode/src/diff/SourceController.ts | 8 +++-- .../tests/unit/source-controller.test.ts | 34 +++++++++++++++++++ 3 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 .changeset/clear-diffs-settle.md diff --git a/.changeset/clear-diffs-settle.md b/.changeset/clear-diffs-settle.md new file mode 100644 index 00000000000..2db456fe67e --- /dev/null +++ b/.changeset/clear-diffs-settle.md @@ -0,0 +1,5 @@ +--- +"kilo-code": patch +--- + +Clear Agent Manager file diff previews stuck on `Loading diff...` when the active diff source stops or changes. diff --git a/packages/kilo-vscode/src/diff/SourceController.ts b/packages/kilo-vscode/src/diff/SourceController.ts index 47d1a771471..11a51ed3449 100644 --- a/packages/kilo-vscode/src/diff/SourceController.ts +++ b/packages/kilo-vscode/src/diff/SourceController.ts @@ -181,8 +181,12 @@ export class SourceController { return } const diff = await source.fetchFile(file).catch(() => null) - // Drop the response if the source has been disposed/swapped while we waited. - if (this.epoch !== epoch) return + // Discard stale content after disposal/swap, but still complete the request + // so consumers can clear per-file loading state. + if (this.epoch !== epoch) { + this.send(this.messages.diffFile(source, file, null)) + return + } this.send(this.messages.diffFile(source, file, diff)) } diff --git a/packages/kilo-vscode/tests/unit/source-controller.test.ts b/packages/kilo-vscode/tests/unit/source-controller.test.ts index f9a49cd2cbc..549fe75af02 100644 --- a/packages/kilo-vscode/tests/unit/source-controller.test.ts +++ b/packages/kilo-vscode/tests/unit/source-controller.test.ts @@ -345,6 +345,40 @@ describe("SourceController.requestFile", () => { controller.stop() }) + + it("posts null when a pending fetchFile result is invalidated by stop", async () => { + let release: () => void = () => {} + const workspace: DiffSource = { + descriptor: WORKSPACE_DESC, + async fetch() { + return { diffs: [] } + }, + async fetchFile() { + await new Promise((resolve) => (release = resolve)) + return { + file: "foo.ts", + before: "a", + after: "b", + additions: 1, + deletions: 1, + } + }, + } + const { controller, posted } = make({ workspace }) + + controller.setContext({ workspaceRoot: "/repo" }) + await controller.activate("workspace") + posted.length = 0 + const request = controller.requestFile("foo.ts") + controller.stop() + release() + await request + + const files = byType(posted, "diffViewer.diffFile") + expect(files).toHaveLength(1) + expect(files[0]!.file).toBe("foo.ts") + expect(files[0]!.diff).toBeNull() + }) }) describe("SourceController.reactivate", () => {