From 0c28c7c0f2a0a369593f09ecd510adcda366c0fc Mon Sep 17 00:00:00 2001 From: "kiloconnect[bot]" <240665456+kiloconnect[bot]@users.noreply.github.com> Date: Wed, 18 Mar 2026 10:02:50 +0000 Subject: [PATCH] fix(vscode): persist notification dismissals so they don't reappear Add optimistic dismiss in the webview so the notification hides immediately when the user clicks X, and update the cached message in KiloProvider so the dismiss survives API failures and offline fallback paths. Previously a dismissed notification could reappear when the webview re-mounted or the CLI backend was temporarily unavailable because the cached payload still contained the old dismissedIds list. --- packages/kilo-vscode/src/KiloProvider.ts | 27 +++++++++++++++++++ .../webview-ui/src/context/notifications.tsx | 1 + 2 files changed, 28 insertions(+) diff --git a/packages/kilo-vscode/src/KiloProvider.ts b/packages/kilo-vscode/src/KiloProvider.ts index a53afedd854..846f14ee388 100644 --- a/packages/kilo-vscode/src/KiloProvider.ts +++ b/packages/kilo-vscode/src/KiloProvider.ts @@ -1404,6 +1404,18 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper private async fetchAndSendNotifications(): Promise { if (!this.client) { if (this.cachedNotificationsMessage) { + // Merge the latest dismissed IDs from globalState into the cached + // message so that dismissals persisted while offline are honoured. + const persisted = this.extensionContext?.globalState.get("kilo.dismissedNotificationIds", []) ?? [] + if (persisted.length > 0) { + const cached = this.cachedNotificationsMessage as { + type: string + notifications: unknown[] + dismissedIds: string[] + } + const merged = Array.from(new Set([...cached.dismissedIds, ...persisted])) + this.cachedNotificationsMessage = { ...cached, dismissedIds: merged } + } this.postMessage(this.cachedNotificationsMessage) } return @@ -1624,6 +1636,21 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper if (!existing.includes(notificationId)) { await this.extensionContext.globalState.update("kilo.dismissedNotificationIds", [...existing, notificationId]) } + // Update the cached message so the dismiss persists even if + // fetchAndSendNotifications() fails (e.g. no client / API error). + if (this.cachedNotificationsMessage) { + const cached = this.cachedNotificationsMessage as { + type: string + notifications: unknown[] + dismissedIds: string[] + } + if (!cached.dismissedIds.includes(notificationId)) { + this.cachedNotificationsMessage = { + ...cached, + dismissedIds: [...cached.dismissedIds, notificationId], + } + } + } await this.fetchAndSendNotifications() this.connectionService.notifyNotificationDismissed(notificationId) } diff --git a/packages/kilo-vscode/webview-ui/src/context/notifications.tsx b/packages/kilo-vscode/webview-ui/src/context/notifications.tsx index 5c45d7a0950..5456cf2cec7 100644 --- a/packages/kilo-vscode/webview-ui/src/context/notifications.tsx +++ b/packages/kilo-vscode/webview-ui/src/context/notifications.tsx @@ -57,6 +57,7 @@ export const NotificationsProvider: ParentComponent = (props) => { }) const dismiss = (id: string) => { + setDismissedIds((prev) => (prev.includes(id) ? prev : [...prev, id])) vscode.postMessage({ type: "dismissNotification", notificationId: id }) }