Skip to content

feat(vscode): add Kilo notifications banner to VS Code extension#437

Open
catrielmuller wants to merge 3 commits intodevfrom
catrielmuller/320-notifications-vscode
Open

feat(vscode): add Kilo notifications banner to VS Code extension#437
catrielmuller wants to merge 3 commits intodevfrom
catrielmuller/320-notifications-vscode

Conversation

@catrielmuller
Copy link
Collaborator

@catrielmuller catrielmuller commented Feb 18, 2026

Context

Resolve: #320

Ports the Kilo news/notifications feature from the CLI (dialog-kilo-notifications.tsx) to the VS Code extension webview. Users can see Kilo news and announcements without needing to open the CLI.

Implementation

The implementation follows the established extension ↔ webview message-passing pattern used for providers, agents, and config:

Extension side (packages/kilo-vscode/src/):

  • types.ts — added KilocodeNotification / KilocodeNotificationAction interfaces
  • index.ts — exported the new types
  • http-client.ts — added getNotifications() calling GET /kilo/notifications (already exists in kilo-gateway)
  • KiloProvider.ts — added fetchAndSendNotifications() with the standard cached-message pattern; handleDismissNotification() persists dismissed IDs to extensionContext.globalState so they survive webview reloads; constructor now accepts optional ExtensionContext
  • extension.ts — passes context to KiloProvider

Webview side (packages/kilo-vscode/webview-ui/src/):

  • types/messages.ts — added NotificationsLoadedMessage, RequestNotificationsMessage, DismissNotificationMessage and wired into unions
  • context/notifications.tsxNotificationsProvider + useNotifications() context; subscribes to notificationsLoaded messages, exposes filteredNotifications() (excludes dismissed), dismiss(id)
  • components/chat/KiloNotifications.tsx — carousel card using kilo-ui Button, IconButton, Icon; pagination (arrow-left/right) on the left, action button on the right in a footer row
  • components/chat/ChatView.tsx — renders <KiloNotifications /> between TaskHeader and messages, wrapped in <Show when={!id()}> so it only appears when no session is active
  • App.tsx — added NotificationsProvider to the provider chain
  • styles/chat.css — added notification card styles using VS Code CSS variables

Key design decisions:

  • Notifications only show on the empty state (no active session), matching the request
  • Dismissed IDs are stored in extensionContext.globalState so they survive webview disposal and VS Code restarts
  • Uses createMemo + direct signal reads (not keyed Show accessor) to ensure total() > 1 re-evaluates reactively for the pagination display

Screenshots

image

Ports the CLI's Kilo news/notifications feature to the VS Code extension.
Shows a dismissable carousel banner at the top of the chat view when no session is active, fetching notifications from the kilo-gateway API with dismissed IDs persisted in extension globalState.
async getNotifications(): Promise<KilocodeNotification[]> {
try {
return await this.request<KilocodeNotification[]>("GET", "/kilo/notifications")
} catch {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[SUGGESTION]: Empty catch block silently swallows errors

Per the project's AGENTS.md style guide: "Never leave a catch block empty." While this follows the existing getProfile() pattern, consider at minimum logging the error so failures are visible:

} catch (err) {
  console.warn("[Kilo] Failed to fetch notifications:", err)
  return []
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, why no logging?

@kiloconnect
Copy link
Contributor

kiloconnect bot commented Feb 18, 2026

Code Review Summary

Status: 4 Issues Found | Recommendation: Address before merge

Overview

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

WARNING

File Line Issue
packages/kilo-vscode/webview-ui/src/context/notifications.tsx 56 showIn field from KilocodeNotification is not being filtered — notifications intended for other surfaces (e.g. TUI-only) will appear in VS Code

SUGGESTION

File Line Issue
packages/kilo-vscode/src/services/cli-backend/http-client.ts 324 Empty catch block silently swallows errors in getNotifications() — consider logging the error for debuggability
packages/kilo-vscode/webview-ui/src/context/notifications.tsx 60 dismiss should optimistically update local dismissedIds signal for instant UI feedback instead of waiting for the round-trip through the extension host
packages/kilo-vscode/src/KiloProvider.ts 907 Dismissed notification IDs accumulate in globalState indefinitely — consider periodic cleanup of IDs that no longer match any active notification
Files Reviewed (9 files)
  • packages/kilo-vscode/src/KiloProvider.ts - 1 issue
  • packages/kilo-vscode/src/extension.ts - 0 issues
  • packages/kilo-vscode/src/services/cli-backend/http-client.ts - 1 issue
  • packages/kilo-vscode/src/services/cli-backend/index.ts - 0 issues
  • packages/kilo-vscode/src/services/cli-backend/types.ts - 0 issues
  • packages/kilo-vscode/webview-ui/src/App.tsx - 0 issues
  • packages/kilo-vscode/webview-ui/src/components/chat/ChatView.tsx - 0 issues
  • packages/kilo-vscode/webview-ui/src/components/chat/KiloNotifications.tsx - 0 issues
  • packages/kilo-vscode/webview-ui/src/context/notifications.tsx - 2 issues
  • packages/kilo-vscode/webview-ui/src/styles/chat.css - 0 issues
  • packages/kilo-vscode/webview-ui/src/types/messages.ts - 0 issues

Fix these issues in Kilo Cloud

if (!this.extensionContext) return
const existing = this.extensionContext.globalState.get<string[]>("kilo.dismissedNotificationIds", [])
if (!existing.includes(notificationId)) {
await this.extensionContext.globalState.update("kilo.dismissedNotificationIds", [...existing, notificationId])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[SUGGESTION]: Dismissed notification IDs accumulate in globalState indefinitely

The kilo.dismissedNotificationIds array grows without bound as users dismiss notifications over time. Consider pruning stale IDs by intersecting with the current notification list, e.g.:

const existing = this.extensionContext.globalState.get<string[]>("kilo.dismissedNotificationIds", [])
const validIds = existing.filter(id => notifications.some(n => n.id === id))
const updated = [...validIds, notificationId]
await this.extensionContext.globalState.update("kilo.dismissedNotificationIds", updated)

This keeps the persisted list from growing with IDs for notifications that no longer exist.

@blacksmith-sh

This comment has been minimized.

@vercel
Copy link

vercel bot commented Feb 19, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
kilo-ui-storybook Ready Ready Preview, Comment Feb 19, 2026 0:58am

Request Review

async getNotifications(): Promise<KilocodeNotification[]> {
try {
return await this.request<KilocodeNotification[]>("GET", "/kilo/notifications")
} catch {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, why no logging?

const items = filteredNotifications
const total = () => items().length
const safeIndex = () => Math.min(index(), Math.max(0, total() - 1))
const current = createMemo(() => items()[safeIndex()])
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is 0 a safe index? this will just return undefined or not?

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.

[FEATURE]: Notifications (VSCode Extension)

2 participants

Comments