diff --git a/packages/kilo-vscode/src/SettingsEditorProvider.ts b/packages/kilo-vscode/src/SettingsEditorProvider.ts index 8a12dd94708..975f36b9255 100644 --- a/packages/kilo-vscode/src/SettingsEditorProvider.ts +++ b/packages/kilo-vscode/src/SettingsEditorProvider.ts @@ -18,6 +18,7 @@ type PanelView = "settings" | "profile" export class SettingsEditorProvider implements vscode.Disposable { private panels = new Map() private providers = new Map() + private tabs = new Map() constructor( private readonly extensionUri: vscode.Uri, @@ -25,9 +26,15 @@ export class SettingsEditorProvider implements vscode.Disposable { private readonly context: vscode.ExtensionContext, ) {} - openPanel(view: PanelView): void { + openPanel(view: PanelView, tab?: string): void { + if (tab) this.tabs.set(view, tab) + const existing = this.panels.get(view) if (existing) { + if (tab) { + const provider = this.providers.get(view) + provider?.postMessage({ type: "navigate", view, tab }) + } existing.reveal(vscode.ViewColumn.One) return } @@ -57,14 +64,21 @@ export class SettingsEditorProvider implements vscode.Disposable { } }) - // Once the webview signals ready, navigate to the target view. + // Navigate to the target view on every webviewReady (including after + // "Developer: Reload Webviews" which re-creates the JS context). const readyDisposable = panel.webview.onDidReceiveMessage((msg) => { if (msg.type === "webviewReady") { // Small delay to let KiloProvider's own webviewReady handler finish first setTimeout(() => { - provider.postMessage({ type: "navigate", view }) + provider.postMessage({ type: "navigate", view, tab: this.tabs.get(view) }) }, 50) - readyDisposable.dispose() + } + }) + + // Remember the active settings tab so it survives webview reloads. + const tabDisposable = panel.webview.onDidReceiveMessage((msg) => { + if (msg.type === "settingsTabChanged" && typeof msg.tab === "string") { + this.tabs.set(view, msg.tab) } }) @@ -74,9 +88,12 @@ export class SettingsEditorProvider implements vscode.Disposable { panel.onDidDispose(() => { console.log(`[Kilo New] ${title} panel disposed`) closePanelDisposable.dispose() + readyDisposable.dispose() + tabDisposable.dispose() provider.dispose() this.panels.delete(view) this.providers.delete(view) + this.tabs.delete(view) }) } diff --git a/packages/kilo-vscode/webview-ui/src/App.tsx b/packages/kilo-vscode/webview-ui/src/App.tsx index 4f4bf317967..8a253a2b40f 100644 --- a/packages/kilo-vscode/webview-ui/src/App.tsx +++ b/packages/kilo-vscode/webview-ui/src/App.tsx @@ -176,6 +176,7 @@ export const LanguageBridge: Component<{ children: any }> = (props) => { // Inner app component that uses the contexts const AppContent: Component = () => { const [currentView, setCurrentView] = createSignal("newTask") + const [settingsTab, setSettingsTab] = createSignal() const [migrationReturnView, setMigrationReturnView] = createSignal("newTask") // legacy-migration const session = useSession() const server = useServer() @@ -212,7 +213,8 @@ const AppContent: Component = () => { handleViewAction(message.action) } if (message?.type === "navigate" && message.view && VALID_VIEWS.has(message.view)) { - console.log("[Kilo New] App: 🧭 navigate:", message.view) + console.log("[Kilo New] App: 🧭 navigate:", message.view, message.tab ? `tab=${message.tab}` : "") + if (message.tab) setSettingsTab(message.tab) setCurrentView(message.view as ViewType) } if (message?.type === "openCloudSession" && message.sessionId) { @@ -267,6 +269,8 @@ const AppContent: Component = () => { { setMigrationReturnView("settings") setCurrentView("migration") diff --git a/packages/kilo-vscode/webview-ui/src/components/settings/Settings.tsx b/packages/kilo-vscode/webview-ui/src/components/settings/Settings.tsx index 816c95cb917..54a626cf1bf 100644 --- a/packages/kilo-vscode/webview-ui/src/components/settings/Settings.tsx +++ b/packages/kilo-vscode/webview-ui/src/components/settings/Settings.tsx @@ -1,6 +1,7 @@ -import { Component } from "solid-js" +import { Component, createSignal, createEffect, on } from "solid-js" import { Icon } from "@kilocode/kilo-ui/icon" import { Tabs } from "@kilocode/kilo-ui/tabs" +import { useVSCode } from "../../context/vscode" import { useLanguage } from "../../context/language" import ProvidersTab from "./ProvidersTab" import AgentBehaviourTab from "./AgentBehaviourTab" @@ -19,12 +20,32 @@ import AboutKiloCodeTab from "./AboutKiloCodeTab" import { useServer } from "../../context/server" export interface SettingsProps { + tab?: string + onTabChange?: (tab: string) => void onMigrateClick?: () => void // legacy-migration } const Settings: Component = (props) => { const server = useServer() const language = useLanguage() + const vscode = useVSCode() + const [active, setActive] = createSignal(props.tab ?? "providers") + + // Sync when the parent changes the tab prop (e.g. via navigate message) + createEffect( + on( + () => props.tab, + (tab) => { + if (tab) setActive(tab) + }, + ), + ) + + const onTabChange = (tab: string) => { + setActive(tab) + props.onTabChange?.(tab) + vscode.postMessage({ type: "settingsTabChanged", tab }) + } return (
@@ -42,7 +63,13 @@ const Settings: Component = (props) => {
{/* Settings tabs */} - + diff --git a/packages/kilo-vscode/webview-ui/src/types/messages.ts b/packages/kilo-vscode/webview-ui/src/types/messages.ts index 8b4543fc5d9..e9fa87dedad 100644 --- a/packages/kilo-vscode/webview-ui/src/types/messages.ts +++ b/packages/kilo-vscode/webview-ui/src/types/messages.ts @@ -557,6 +557,7 @@ export interface DeviceAuthCancelledMessage { export interface NavigateMessage { type: "navigate" view: "newTask" | "marketplace" | "history" | "cloudHistory" | "profile" | "settings" | "migration" | "subAgentViewer" // legacy-migration: "migration" + tab?: string } export interface ProvidersLoadedMessage { @@ -1327,6 +1328,11 @@ export interface ResetAllSettingsRequest { type: "resetAllSettings" } +export interface SettingsTabChangedMessage { + type: "settingsTabChanged" + tab: string +} + export interface RequestNotificationsMessage { type: "requestNotifications" } @@ -1638,6 +1644,7 @@ export type WebviewMessage = | UpdateConfigMessage | RequestNotificationSettingsMessage | ResetAllSettingsRequest + | SettingsTabChangedMessage | SyncSessionRequest | CreateWorktreeSessionRequest | RequestNotificationsMessage