diff --git a/packages/kilo-vscode/src/KiloProvider.ts b/packages/kilo-vscode/src/KiloProvider.ts index 4289cb2fe4a..3cd0d0dff26 100644 --- a/packages/kilo-vscode/src/KiloProvider.ts +++ b/packages/kilo-vscode/src/KiloProvider.ts @@ -16,6 +16,8 @@ export class KiloProvider implements vscode.WebviewViewProvider { /** Cached configLoaded payload so requestConfig can be served before httpClient is ready */ private cachedConfigMessage: unknown = null + private readonly globalState: vscode.Memento + private trackedSessionIds: Set = new Set() private unsubscribeEvent: (() => void) | null = null private unsubscribeState: (() => void) | null = null @@ -24,7 +26,10 @@ export class KiloProvider implements vscode.WebviewViewProvider { constructor( private readonly extensionUri: vscode.Uri, private readonly connectionService: KiloConnectionService, - ) {} + globalState: vscode.Memento, + ) { + this.globalState = globalState + } /** * Convenience getter that returns the shared HttpClient or null if not yet connected. @@ -234,6 +239,12 @@ export class KiloProvider implements vscode.WebviewViewProvider { case "requestBrowserSettings": this.sendBrowserSettings() break + case "requestLocalSettings": + await this.handleRequestLocalSettings() + break + case "saveLocalSetting": + await this.handleSaveLocalSetting(message.key, message.value) + break } }) } @@ -316,6 +327,7 @@ export class KiloProvider implements vscode.WebviewViewProvider { await this.fetchAndSendProviders() await this.fetchAndSendAgents() await this.fetchAndSendConfig() + await this.handleRequestLocalSettings() console.log("[Kilo New] KiloProvider: ✅ initializeConnection completed successfully") } catch (error) { @@ -623,6 +635,32 @@ export class KiloProvider implements vscode.WebviewViewProvider { } } + /** + * Send all local settings to the webview. + */ + private async handleRequestLocalSettings(): Promise { + const keys = [ + "notifications.agent", + "notifications.permissions", + "notifications.errors", + "sounds.agent", + "sounds.permissions", + "sounds.errors", + ] + const settings: Record = {} + for (const key of keys) { + settings[key] = this.globalState.get(key) + } + this.postMessage({ type: "localSettingsLoaded", settings }) + } + + /** + * Save a local setting to globalState. + */ + private async handleSaveLocalSetting(key: string, value: unknown): Promise { + await this.globalState.update(key, value) + } + /** * Handle config update request from the webview. * Applies a partial config update, then re-fetches and pushes the full config. diff --git a/packages/kilo-vscode/src/extension.ts b/packages/kilo-vscode/src/extension.ts index a2e23a764de..6218e1f3ade 100644 --- a/packages/kilo-vscode/src/extension.ts +++ b/packages/kilo-vscode/src/extension.ts @@ -23,7 +23,7 @@ export function activate(context: vscode.ExtensionContext) { }) // Create the provider with shared service - const provider = new KiloProvider(context.extensionUri, connectionService) + const provider = new KiloProvider(context.extensionUri, connectionService, context.globalState) // Register the webview view provider for the sidebar context.subscriptions.push(vscode.window.registerWebviewViewProvider(KiloProvider.viewType, provider)) @@ -91,7 +91,7 @@ async function openKiloInNewTab(context: vscode.ExtensionContext, connectionServ dark: vscode.Uri.joinPath(context.extensionUri, "assets", "icons", "kilo-dark.svg"), } - const tabProvider = new KiloProvider(context.extensionUri, connectionService) + const tabProvider = new KiloProvider(context.extensionUri, connectionService, context.globalState) tabProvider.resolveWebviewPanel(panel) // Wait for the new panel to become active before locking the editor group. diff --git a/packages/kilo-vscode/webview-ui/src/components/settings/NotificationsTab.tsx b/packages/kilo-vscode/webview-ui/src/components/settings/NotificationsTab.tsx index b6057ef0118..3d4f683827d 100644 --- a/packages/kilo-vscode/webview-ui/src/components/settings/NotificationsTab.tsx +++ b/packages/kilo-vscode/webview-ui/src/components/settings/NotificationsTab.tsx @@ -1,29 +1,200 @@ -import { Component } from "solid-js" +import { Component, createSignal, onCleanup } from "solid-js" +import { useVSCode } from "../../context/vscode" +import type { ExtensionMessage } from "../../types/messages" const NotificationsTab: Component = () => { + const vscode = useVSCode() + + const [agentNotify, setAgentNotify] = createSignal(true) + const [permNotify, setPermNotify] = createSignal(true) + const [errorNotify, setErrorNotify] = createSignal(true) + const [agentSound, setAgentSound] = createSignal("default") + const [permSound, setPermSound] = createSignal("default") + const [errorSound, setErrorSound] = createSignal("default") + + // Listen for local settings loaded + const unsubscribe = vscode.onMessage((message: ExtensionMessage) => { + if (message.type !== "localSettingsLoaded") { + return + } + const s = message.settings + if (s["notifications.agent"] !== undefined) { + setAgentNotify(s["notifications.agent"] as boolean) + } + if (s["notifications.permissions"] !== undefined) { + setPermNotify(s["notifications.permissions"] as boolean) + } + if (s["notifications.errors"] !== undefined) { + setErrorNotify(s["notifications.errors"] as boolean) + } + if (s["sounds.agent"] !== undefined) { + setAgentSound(s["sounds.agent"] as string) + } + if (s["sounds.permissions"] !== undefined) { + setPermSound(s["sounds.permissions"] as string) + } + if (s["sounds.errors"] !== undefined) { + setErrorSound(s["sounds.errors"] as string) + } + }) + + onCleanup(unsubscribe) + + // Request settings + vscode.postMessage({ type: "requestLocalSettings" }) + + const saveSetting = (key: string, value: unknown) => { + vscode.postMessage({ type: "saveLocalSetting", key, value }) + } + + const selectStyle = { + padding: "4px 8px", + "border-radius": "4px", + border: "1px solid var(--vscode-dropdown-border, var(--vscode-panel-border))", + background: "var(--vscode-dropdown-background)", + color: "var(--vscode-dropdown-foreground)", + "font-size": "12px", + "font-family": "var(--vscode-font-family)", + cursor: "pointer", + outline: "none", + "min-width": "100px", + } + + interface RowProps { + label: string + description: string + last?: boolean + children: any + } + + const Row: Component = (props) => ( +
+
+
+ {props.label} +
+
+ {props.description} +
+
+ {props.children} +
+ ) + return (
+ {/* Notification toggles */} +

+ Notifications +

-

- This section is not implemented yet. It will - contain configuration options and explanatory text related to the selected settings category. During - reimplementation, use this space to validate layout, spacing, scrolling behavior, and navigation state before - wiring up real controls. -

+ + + + + + + + + +
+ + {/* Sound settings */} +

+ Sounds +

+
+ + + + + + + + +
) diff --git a/packages/kilo-vscode/webview-ui/src/types/messages.ts b/packages/kilo-vscode/webview-ui/src/types/messages.ts index 4645289aaf6..6188e3ff97b 100644 --- a/packages/kilo-vscode/webview-ui/src/types/messages.ts +++ b/packages/kilo-vscode/webview-ui/src/types/messages.ts @@ -450,6 +450,11 @@ export interface ConfigUpdatedMessage { config: Config } +export interface LocalSettingsLoadedMessage { + type: "localSettingsLoaded" + settings: Record +} + export type ExtensionMessage = | ReadyMessage | ConnectionStateMessage @@ -478,6 +483,7 @@ export type ExtensionMessage = | BrowserSettingsLoadedMessage | ConfigLoadedMessage | ConfigUpdatedMessage + | LocalSettingsLoadedMessage // ============================================ // Messages FROM webview TO extension @@ -607,6 +613,16 @@ export interface UpdateConfigMessage { config: Partial } +export interface SaveLocalSettingMessage { + type: "saveLocalSetting" + key: string + value: unknown +} + +export interface RequestLocalSettingsMessage { + type: "requestLocalSettings" +} + export type WebviewMessage = | SendMessageRequest | AbortRequest @@ -633,6 +649,8 @@ export type WebviewMessage = | RequestBrowserSettingsMessage | RequestConfigMessage | UpdateConfigMessage + | SaveLocalSettingMessage + | RequestLocalSettingsMessage // ============================================ // VS Code API type