Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 083e21c68d |
@@ -162,7 +162,6 @@
|
||||
unzip
|
||||
gnutar
|
||||
gzip
|
||||
ripgrep
|
||||
kilo-dev
|
||||
kilo-install-bin
|
||||
kilo-bin
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user