Compare commits

...

1 Commits

Author SHA1 Message Date
marius-kilocode 083e21c68d revert: remove vscode notifications feature (PR #437 and #531)
The notification banner in the VS Code extension sidebar needs more
work before shipping. This reverts the notification infrastructure
(context, component, provider wiring, styles, types, and backend
client method) while preserving the extensionContext plumbing used
by the variant-selection feature.
2026-02-20 22:15:53 +01:00
11 changed files with 9 additions and 366 deletions
-1
View File
@@ -162,7 +162,6 @@
unzip
gnutar
gzip
ripgrep
kilo-dev
kilo-install-bin
kilo-bin
+1 -56
View File
@@ -1,12 +1,6 @@
import * as vscode from "vscode"
import { z } from "zod"
import {
type HttpClient,
type SessionInfo,
type SSEEvent,
type KiloConnectionService,
type KilocodeNotification,
} from "./services/cli-backend"
import { type HttpClient, type SessionInfo, type SSEEvent, type KiloConnectionService } from "./services/cli-backend"
import { handleChatCompletionRequest } from "./services/autocomplete/chat-autocomplete/handleChatCompletionRequest"
import { handleChatCompletionAccepted } from "./services/autocomplete/chat-autocomplete/handleChatCompletionAccepted"
import { buildWebviewHtml } from "./utils"
@@ -35,8 +29,6 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
private cachedAgentsMessage: unknown = null
/** Cached configLoaded payload so requestConfig can be served before httpClient is ready */
private cachedConfigMessage: unknown = null
/** Cached notificationsLoaded payload */
private cachedNotificationsMessage: unknown = null
private trackedSessionIds: Set<string> = new Set()
/** Per-session directory overrides (e.g., worktree paths registered by AgentManagerProvider). */
@@ -428,12 +420,6 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
case "requestNotificationSettings":
this.sendNotificationSettings()
break
case "requestNotifications":
await this.fetchAndSendNotifications()
break
case "dismissNotification":
await this.handleDismissNotification(message.notificationId)
break
case "resetAllSettings":
await this.handleResetAllSettings()
break
@@ -534,7 +520,6 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
await this.fetchAndSendProviders()
await this.fetchAndSendAgents()
await this.fetchAndSendConfig()
await this.fetchAndSendNotifications()
this.sendNotificationSettings()
console.log("[Kilo New] KiloProvider: ✅ initializeConnection completed successfully")
@@ -917,46 +902,6 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
}
}
/**
* Fetch Kilo news/notifications and send to webview.
* Uses the cached message pattern so the webview gets data immediately on refresh.
*/
private async fetchAndSendNotifications(): Promise<void> {
if (!this.httpClient) {
if (this.cachedNotificationsMessage) {
this.postMessage(this.cachedNotificationsMessage)
}
return
}
try {
const notifications = await this.httpClient.getNotifications()
const existing = this.extensionContext?.globalState.get<string[]>("kilo.dismissedNotificationIds", []) ?? []
const active = new Set(notifications.map((n) => n.id))
const dismissedIds = existing.filter((id) => active.has(id))
if (dismissedIds.length !== existing.length) {
await this.extensionContext?.globalState.update("kilo.dismissedNotificationIds", dismissedIds)
}
const message = { type: "notificationsLoaded", notifications, dismissedIds }
this.cachedNotificationsMessage = message
this.postMessage(message)
} catch (error) {
console.error("[Kilo New] KiloProvider: Failed to fetch notifications:", error)
}
}
/**
* Persist a dismissed notification ID in globalState and push updated lists to webview.
*/
private async handleDismissNotification(notificationId: string): Promise<void> {
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])
}
await this.fetchAndSendNotifications()
}
/**
* Read notification/sound settings from VS Code config and push to webview.
*/
@@ -11,7 +11,6 @@ import type {
McpStatus,
McpConfig,
Config,
KilocodeNotification,
} from "./types"
import { extractHttpErrorMessage, parseSSEDataLine } from "./http-utils"
@@ -327,19 +326,6 @@ export class HttpClient {
}
}
/**
* Fetch Kilo notifications for the current user from the kilo-gateway.
* Returns an empty array if not logged in or if the request fails.
*/
async getNotifications(): Promise<KilocodeNotification[]> {
try {
return await this.request<KilocodeNotification[]>("GET", "/kilo/notifications")
} catch (err) {
console.warn("[Kilo] Failed to fetch notifications:", err)
return []
}
}
/**
* Switch the active organization.
* Pass null to switch back to personal account.
@@ -26,8 +26,6 @@ export type {
McpRemoteConfig,
McpConfig,
Config,
KilocodeNotification,
KilocodeNotificationAction,
} from "./types"
export { ServerManager } from "./server-manager"
@@ -176,20 +176,6 @@ export interface ProviderAuthAuthorization {
instructions: string
}
// Kilo notification from kilo-gateway
export interface KilocodeNotificationAction {
actionText: string
actionURL: string
}
export interface KilocodeNotification {
id: string
title: string
message: string
action?: KilocodeNotificationAction
showIn?: string[]
}
// Profile types from kilo-gateway
export interface KilocodeOrganization {
id: string
+5 -8
View File
@@ -18,7 +18,6 @@ import { SessionProvider, useSession } from "./context/session"
import { LanguageProvider } from "./context/language"
import { ChatView } from "./components/chat"
import SessionList from "./components/history/SessionList"
import { NotificationsProvider } from "./context/notifications"
import type { Message as SDKMessage, Part as SDKPart } from "@kilocode/sdk/v2"
import "./styles/chat.css"
@@ -190,13 +189,11 @@ const App: Component = () => {
<CodeComponentProvider component={Code}>
<ProviderProvider>
<ConfigProvider>
<NotificationsProvider>
<SessionProvider>
<DataBridge>
<AppContent />
</DataBridge>
</SessionProvider>
</NotificationsProvider>
<SessionProvider>
<DataBridge>
<AppContent />
</DataBridge>
</SessionProvider>
</ConfigProvider>
</ProviderProvider>
</CodeComponentProvider>
@@ -10,7 +10,6 @@ import { TaskHeader } from "./TaskHeader"
import { MessageList } from "./MessageList"
import { PromptInput } from "./PromptInput"
import { QuestionDock } from "./QuestionDock"
import { KiloNotifications } from "./KiloNotifications"
import { useSession } from "../../context/session"
import { useLanguage } from "../../context/language"
@@ -55,13 +54,8 @@ export const ChatView: Component<ChatViewProps> = (props) => {
return (
<div class="chat-view">
<TaskHeader />
<div class="chat-messages-wrapper">
<Show when={!id()}>
<KiloNotifications />
</Show>
<div class="chat-messages">
<MessageList onSelectSession={props.onSelectSession} />
</div>
<div class="chat-messages">
<MessageList onSelectSession={props.onSelectSession} />
</div>
<Show when={!props.readonly}>
@@ -1,67 +0,0 @@
import { Component, Show, createMemo, createSignal } from "solid-js"
import { Button } from "@kilocode/kilo-ui/button"
import { IconButton } from "@kilocode/kilo-ui/icon-button"
import { Icon } from "@kilocode/kilo-ui/icon"
import { useNotifications } from "../../context/notifications"
import { useVSCode } from "../../context/vscode"
export const KiloNotifications: Component = () => {
const { filteredNotifications, dismiss } = useNotifications()
const vscode = useVSCode()
const [index, setIndex] = createSignal(0)
const items = filteredNotifications
const total = () => items().length
const safeIndex = () => Math.min(index(), Math.max(0, total() - 1))
const current = createMemo(() => (total() === 0 ? undefined : items()[safeIndex()]))
const prev = () => setIndex((i) => (i - 1 + total()) % total())
const next = () => setIndex((i) => (i + 1) % total())
const handleAction = (url: string) => {
vscode.postMessage({ type: "openExternal", url })
}
const handleDismiss = () => {
const n = current()
if (!n) return
dismiss(n.id)
setIndex((i) => Math.min(i, Math.max(0, total() - 2)))
}
return (
<Show when={total() > 0}>
<div class="kilo-notifications">
<div class="kilo-notifications-card">
<div class="kilo-notifications-header">
<span class="kilo-notifications-title">{current()?.title}</span>
<IconButton size="small" variant="ghost" icon="close" onClick={handleDismiss} title="Dismiss" />
</div>
<p class="kilo-notifications-message">{current()?.message}</p>
<div class="kilo-notifications-footer">
<Show when={total() > 1}>
<div class="kilo-notifications-nav">
<button class="kilo-notifications-nav-btn" onClick={prev} title="Previous">
<Icon name="arrow-left" size="small" />
</button>
<span class="kilo-notifications-nav-count">
{safeIndex() + 1} / {total()}
</span>
<button class="kilo-notifications-nav-btn" onClick={next} title="Next">
<Icon name="arrow-right" size="small" />
</button>
</div>
</Show>
<Show when={current()?.action}>
{(action) => (
<Button variant="primary" size="small" onClick={() => handleAction(action().actionURL)}>
{action().actionText}
</Button>
)}
</Show>
</div>
</div>
</div>
</Show>
)
}
@@ -1,78 +0,0 @@
import {
createContext,
useContext,
createSignal,
createMemo,
onMount,
onCleanup,
ParentComponent,
Accessor,
} from "solid-js"
import { useVSCode } from "./vscode"
import type { KilocodeNotification, ExtensionMessage } from "../types/messages"
interface NotificationsContextValue {
notifications: Accessor<KilocodeNotification[]>
filteredNotifications: Accessor<KilocodeNotification[]>
dismiss: (id: string) => void
}
const NotificationsContext = createContext<NotificationsContextValue>()
export const NotificationsProvider: ParentComponent = (props) => {
const vscode = useVSCode()
const [notifications, setNotifications] = createSignal<KilocodeNotification[]>([])
const [dismissedIds, setDismissedIds] = createSignal<string[]>([])
const unsubscribe = vscode.onMessage((message: ExtensionMessage) => {
if (message.type === "notificationsLoaded") {
setNotifications(message.notifications)
setDismissedIds(message.dismissedIds)
}
})
onMount(() => {
let retries = 0
const request = () => {
vscode.postMessage({ type: "requestNotifications" })
}
request()
const interval = setInterval(() => {
if (notifications().length > 0 || retries >= 5) {
clearInterval(interval)
return
}
retries++
request()
}, 500)
onCleanup(() => {
clearInterval(interval)
unsubscribe()
})
})
const filteredNotifications = createMemo(() => {
const dismissed = dismissedIds()
return notifications().filter((n) => !dismissed.includes(n.id))
})
const dismiss = (id: string) => {
vscode.postMessage({ type: "dismissNotification", notificationId: id })
}
const value: NotificationsContextValue = {
notifications,
filteredNotifications,
dismiss,
}
return <NotificationsContext.Provider value={value}>{props.children}</NotificationsContext.Provider>
}
export function useNotifications(): NotificationsContextValue {
const context = useContext(NotificationsContext)
if (!context) {
throw new Error("useNotifications must be used within a NotificationsProvider")
}
return context
}
@@ -14,15 +14,8 @@
overflow: hidden;
}
.chat-messages-wrapper {
position: relative;
flex: 1;
overflow: hidden;
min-height: 0;
}
.chat-messages {
height: 100%;
flex: 1;
overflow: hidden;
min-height: 0;
}
@@ -754,81 +747,3 @@
color: var(--text-weak, var(--vscode-descriptionForeground));
white-space: nowrap;
}
/* ============================================
Kilo Notifications
============================================ */
.kilo-notifications {
position: absolute;
top: 0;
left: 0;
width: 100%;
z-index: 10;
display: flex;
flex-direction: column;
border-bottom: 1px solid var(--vscode-panel-border);
}
.kilo-notifications-card {
background-color: var(--vscode-editor-background);
padding: 12px;
display: flex;
flex-direction: column;
gap: 8px;
}
.kilo-notifications-header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
}
.kilo-notifications-title {
font-weight: 600;
color: var(--vscode-foreground);
font-size: 13px;
flex: 1;
}
.kilo-notifications-message {
margin: 0;
color: var(--vscode-descriptionForeground);
font-size: 12px;
line-height: 1.5;
}
.kilo-notifications-footer {
display: flex;
align-items: center;
justify-content: space-between;
min-height: 28px;
}
.kilo-notifications-nav {
display: flex;
align-items: center;
gap: 2px;
}
.kilo-notifications-nav-btn {
background: none;
border: none;
cursor: pointer;
padding: 2px 4px;
color: var(--vscode-descriptionForeground);
display: inline-flex;
align-items: center;
}
.kilo-notifications-nav-btn:hover {
color: var(--vscode-foreground);
}
.kilo-notifications-nav-count {
font-size: 12px;
color: var(--vscode-descriptionForeground);
white-space: nowrap;
padding: 0 4px;
}
@@ -174,20 +174,6 @@ export interface DeviceAuthState {
error?: string
}
// Kilo notification types (mirrored from kilo-gateway)
export interface KilocodeNotificationAction {
actionText: string
actionURL: string
}
export interface KilocodeNotification {
id: string
title: string
message: string
action?: KilocodeNotificationAction
showIn?: string[]
}
// Profile types from kilo-gateway
export interface KilocodeBalance {
balance: number
@@ -528,12 +514,6 @@ export interface NotificationSettingsLoadedMessage {
}
}
export interface NotificationsLoadedMessage {
type: "notificationsLoaded"
notifications: KilocodeNotification[]
dismissedIds: string[]
}
// Agent Manager worktree session metadata
export interface AgentManagerSessionMetaMessage {
type: "agentManager.sessionMeta"
@@ -660,7 +640,6 @@ export type ExtensionMessage =
| ConfigLoadedMessage
| ConfigUpdatedMessage
| NotificationSettingsLoadedMessage
| NotificationsLoadedMessage
| AgentManagerSessionMetaMessage
| AgentManagerRepoInfoMessage
| AgentManagerWorktreeSetupMessage
@@ -854,15 +833,6 @@ export interface ResetAllSettingsRequest {
type: "resetAllSettings"
}
export interface RequestNotificationsMessage {
type: "requestNotifications"
}
export interface DismissNotificationMessage {
type: "dismissNotification"
notificationId: string
}
export interface SyncSessionRequest {
type: "syncSession"
sessionID: string
@@ -1006,8 +976,6 @@ export type WebviewMessage =
| ResetAllSettingsRequest
| SyncSessionRequest
| CreateWorktreeSessionRequest
| RequestNotificationsMessage
| DismissNotificationMessage
| CreateWorktreeRequest
| DeleteWorktreeRequest
| PromoteSessionRequest