Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
5df7aa4
fix(vscode): clear unsent drafts on session deletion
IamCoder18 Jun 19, 2026
494817d
fix(vscode): prevent draftKey effect from recreating deleted-session …
IamCoder18 Jun 19, 2026
f310d46
Merge branch 'main' into vscode/cleanup-drafts-on-session-delete
IamCoder18 Jun 19, 2026
152cf66
fix(vscode): forward external session deletions and decouple draft id…
IamCoder18 Jun 19, 2026
d4be9ec
fix(vscode): don't re-track deleted sessions and purge per-session mo…
IamCoder18 Jun 19, 2026
67691a2
fix(vscode): prune per-session state on every deletion path
IamCoder18 Jun 19, 2026
8b7f1ab
merge: upstream main into vscode/cleanup-drafts-on-session-delete
IamCoder18 Jun 19, 2026
faa47d0
fix(vscode): drop sessionStatusMap and respondingPermissions on delete
IamCoder18 Jun 19, 2026
fbe5f4c
fix(vscode): recover from external session deletes during send
IamCoder18 Jun 23, 2026
2db9934
Merge branch 'main' into vscode/cleanup-drafts-on-session-delete
IamCoder18 Jun 23, 2026
2a3f0b0
fix(vscode): restore failed draft into current bucket, not stale session
IamCoder18 Jun 23, 2026
9fc017c
fix(vscode): only restore failed draft into buckets the send was scop…
IamCoder18 Jun 23, 2026
454d35c
fix(vscode): accept :new as restoreFailed candidate when user is back…
IamCoder18 Jun 23, 2026
68f70e2
fix(vscode): suppress :new restoreFailed candidate after user-initiat…
IamCoder18 Jun 23, 2026
1974ddc
fix(vscode): early-return restoreFailed when user explicitly cleared …
IamCoder18 Jun 24, 2026
409ea5f
docs(changeset): note mid-send restore recovery in cleanup-drafts cha…
IamCoder18 Jun 24, 2026
b36b740
fix(vscode): clear userClearedSession when user starts a new draft fr…
IamCoder18 Jun 24, 2026
74f9bf6
Merge branch 'main' into vscode/cleanup-drafts-on-session-delete
IamCoder18 Jun 24, 2026
0601898
fix(vscode): reset userClearedSession on cloud session select and import
IamCoder18 Jun 30, 2026
a63517e
fix(vscode): migrate draftSessionID and prune cloud parts on import
IamCoder18 Jun 30, 2026
b9febc6
fix(vscode): clear draftSessionID on cloudSessionImportFailed
IamCoder18 Jun 30, 2026
0c91183
fix(vscode): guard draftSessionID clear on cloud import failure
IamCoder18 Jun 30, 2026
12ee9ef
fix(vscode): guard currentSessionID clear on cloud import failure
IamCoder18 Jun 30, 2026
733d11d
fix(vscode): guard cloudPreviewId clear on cloud import failure
IamCoder18 Jun 30, 2026
57c09d2
fix(vscode): guard loading clear on cloud import failure
IamCoder18 Jun 30, 2026
37bbbd0
fix(vscode): order loading clear before cloudPreviewId clear on failure
IamCoder18 Jun 30, 2026
9d3b150
Merge remote-tracking branch 'upstream/main' into vscode/cleanup-draf…
IamCoder18 Jun 30, 2026
5eabe93
refactor(vscode): extract cloud-prune helpers and compact session.tsx
IamCoder18 Jul 1, 2026
e4f98ca
fix(vscode): move createCloudPrune inside SessionProvider
IamCoder18 Jul 1, 2026
80a8ee0
fix(vscode): restore prompt-send contract shapes after cloud-prune re…
IamCoder18 Jul 1, 2026
14f6f2d
test(vscode): exercise clearIfOn helper instead of source-grep
IamCoder18 Jul 1, 2026
8f251ad
style(vscode): fix Prettier formatting in KiloProvider.ts
IamCoder18 Jul 1, 2026
3795ae0
fix(vscode): clear cloud preview state on import failure using raw se…
marius-kilocode Jul 3, 2026
d650fb5
Merge origin/main into vscode/cleanup-drafts-on-session-delete
marius-kilocode Jul 3, 2026
33206d7
refactor(vscode): compact session delete cleanup to satisfy max-lines
marius-kilocode Jul 3, 2026
30acec7
refactor(vscode): reduce diff noise vs main
marius-kilocode Jul 3, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/cleanup-drafts-on-session-delete.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"kilo-code": patch
---

Free webview memory for deleted VS Code sessions by clearing unsent prompt text, review comments, and pending image attachments that were retained in the per-session draft cache after `sessionDeleted`.
33 changes: 32 additions & 1 deletion packages/kilo-vscode/tests/unit/prompt-drafts.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,37 @@
import { describe, it, expect } from "bun:test"
import { beforeEach, describe, it, expect } from "bun:test"
import { deleteDraftsForSession, drafts, imageDrafts, reviewDrafts } from "../../webview-ui/src/utils/draft-store"
import { pendingDraftKey, scopeDraftKey, sessionDraftKey } from "../../webview-ui/src/utils/prompt-drafts"

beforeEach(() => {
drafts.clear()
reviewDrafts.clear()
imageDrafts.clear()
})

describe("deleteDraftsForSession", () => {
it("clears deleted-session drafts without touching other sessions", () => {
drafts.set("prompt:default:session:a", "draft a")
drafts.set("prompt:default:pending:a", "pending a")
drafts.set("prompt:default:session:b", "draft b")
reviewDrafts.set("prompt:default:session:a", [])
imageDrafts.set("prompt:default:session:a", [])

deleteDraftsForSession("a")

expect(drafts.has("prompt:default:session:a")).toBe(false)
expect(drafts.has("prompt:default:pending:a")).toBe(false)
expect(drafts.get("prompt:default:session:b")).toBe("draft b")
expect(reviewDrafts.has("prompt:default:session:a")).toBe(false)
expect(imageDrafts.has("prompt:default:session:a")).toBe(false)
})

it("is a no-op when given an empty id", () => {
drafts.set("prompt:default:session:a", "draft a")
deleteDraftsForSession("")
expect(drafts.get("prompt:default:session:a")).toBe("draft a")
})
})

describe("sessionDraftKey", () => {
it("prefixes session ids", () => {
expect(sessionDraftKey("abc")).toBe("session:abc")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,10 @@ import {
import type { ReviewComment, SendMessageFailedMessage, TextPart } from "../../types/messages"
import { formatReviewCommentsMarkdown } from "../../utils/review-comment-markdown"
import { pendingDraftKey, scopeDraftKey, sessionDraftKey } from "../../utils/prompt-drafts"
import { drafts, imageDrafts, reviewDrafts } from "../../utils/draft-store"
import { ReviewComments } from "./ReviewComments"
import { partReview, reviewBody } from "../../../../src/shared/review-comments"

// Per-session input text storage (module-level so it survives remounts)
const drafts = new Map<string, string>()
const reviewDrafts = new Map<string, ReviewComment[]>()
const imageDrafts = new Map<string, ImageAttachment[]>()

function mergeReviewComments(current: ReviewComment[], incoming: ReviewComment[]): ReviewComment[] {
if (incoming.length === 0) return current
const map = new Map(current.map((item) => [item.id, item]))
Expand Down
2 changes: 2 additions & 0 deletions packages/kilo-vscode/webview-ui/src/context/session.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ import { getVariant, sessionVariantKeys, transferVariants, variantKey } from "./
import { KILO_AUTO, KILO_PROVIDER_ID, parseModelString } from "../../../src/shared/provider-model"
import { reviewMetadata, type ReviewMessageData } from "../../../src/shared/review-comments"
import { visibleMessages as filterVisibleMessages } from "./session-queue"
import { deleteDraftsForSession } from "../utils/draft-store"
import { createAbortState } from "./abort-state"

const RECENT_LIMIT = 5
Expand Down Expand Up @@ -1910,6 +1911,7 @@ export const SessionProvider: ParentComponent = (props) => {
delete map[sessionID]
}),
)
deleteDraftsForSession(sessionID)
Comment thread
IamCoder18 marked this conversation as resolved.
Outdated
if (currentSessionID() === sessionID) {
setCurrentSessionID(undefined)
setLoading(false)
Expand Down
21 changes: 21 additions & 0 deletions packages/kilo-vscode/webview-ui/src/utils/draft-store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type { ReviewComment } from "../types/messages"
import type { ImageAttachment } from "../hooks/useImageAttachments"

export const drafts = new Map<string, string>()
export const reviewDrafts = new Map<string, ReviewComment[]>()
export const imageDrafts = new Map<string, ImageAttachment[]>()

export function deleteDraftsForSession(id: string) {
if (!id) return
const sessionSuffix = `:session:${id}`
const pendingSuffix = `:pending:${id}`
const maps = [drafts, reviewDrafts, imageDrafts]
for (const map of maps) {
for (const key of map.keys()) {
if (typeof key !== "string") continue
if (key.endsWith(sessionSuffix) || key.endsWith(pendingSuffix)) {
map.delete(key)
}
}
}
}
Loading