Merge pull request #7379 from Kilo-Org/catrielmuller/refresh-vscode-panels-on-update

fix(vscode): restore webview panels on extension restart/update
This commit is contained in:
Catriel Müller
2026-03-20 16:40:07 -03:00
committed by GitHub
4 changed files with 108 additions and 12 deletions
+7 -1
View File
@@ -45,7 +45,13 @@
"kilocode"
],
"activationEvents": [
"onWebviewPanel:kilo-code.new.AgentManagerPanel"
"onWebviewPanel:kilo-code.new.AgentManagerPanel",
"onWebviewPanel:kilo-code.new.TabPanel",
"onWebviewPanel:kilo-code.new.settingsPanel",
"onWebviewPanel:kilo-code.new.profilePanel",
"onWebviewPanel:kilo-code.new.marketplacePanel",
"onWebviewPanel:kilo-code.new.DiffViewerPanel",
"onWebviewPanel:kilo-code.new.SubAgentViewerPanel"
],
"main": "./dist/extension.js",
"contributes": {
+16 -5
View File
@@ -48,21 +48,32 @@ export class DiffViewerProvider implements vscode.Disposable {
return
}
this.panel = vscode.window.createWebviewPanel(DiffViewerProvider.viewType, "Changes", vscode.ViewColumn.One, {
const panel = vscode.window.createWebviewPanel(DiffViewerProvider.viewType, "Changes", vscode.ViewColumn.One, {
enableScripts: true,
retainContextWhenHidden: true,
localResourceRoots: [this.extensionUri],
})
this.panel.iconPath = {
this.wirePanel(panel)
}
/** Re-wire a deserialized panel after extension restart. */
public deserializePanel(panel: vscode.WebviewPanel): void {
this.wirePanel(panel)
}
private wirePanel(panel: vscode.WebviewPanel): void {
this.panel = panel
panel.iconPath = {
light: vscode.Uri.joinPath(this.extensionUri, "assets", "icons", "kilo-light.svg"),
dark: vscode.Uri.joinPath(this.extensionUri, "assets", "icons", "kilo-dark.svg"),
}
this.panel.webview.onDidReceiveMessage((msg) => this.onMessage(msg), undefined, [])
this.panel.webview.html = this.getHtml(this.panel.webview)
panel.webview.onDidReceiveMessage((msg) => this.onMessage(msg), undefined, [])
panel.webview.html = this.getHtml(panel.webview)
this.panel.onDidDispose(() => {
panel.onDidDispose(() => {
this.log("Panel disposed")
this.stopDiffPolling()
this.panel = undefined
@@ -42,6 +42,15 @@ export class SettingsEditorProvider implements vscode.Disposable {
return resolvePanelProjectDirectory(active, vscode.workspace.workspaceFolders)
}
/** Extract the PanelView from a viewType string like "kilo-code.new.settingsPanel". */
static viewFromType(type: string): PanelView | undefined {
const match = type.match(/^kilo-code\.new\.(\w+)Panel$/)
if (!match) return undefined
const view = match[1] as PanelView
if (!(view in PANEL_TITLES)) return undefined
return view
}
openPanel(view: PanelView, tab?: string): void {
if (tab) this.tabs.set(view, tab)
@@ -57,14 +66,31 @@ export class SettingsEditorProvider implements vscode.Disposable {
return
}
const title = PANEL_TITLES[view]
const panel = vscode.window.createWebviewPanel(
`kilo-code.new.${view}Panel`,
PANEL_TITLES[view],
vscode.ViewColumn.One,
{
enableScripts: true,
retainContextWhenHidden: true,
localResourceRoots: [this.extensionUri],
},
)
const panel = vscode.window.createWebviewPanel(`kilo-code.new.${view}Panel`, title, vscode.ViewColumn.One, {
enableScripts: true,
retainContextWhenHidden: true,
localResourceRoots: [this.extensionUri],
})
this.wirePanel(panel, view, projectDirectory)
}
/** Re-wire a deserialized panel after extension restart. */
deserializePanel(panel: vscode.WebviewPanel): void {
const view = SettingsEditorProvider.viewFromType(panel.viewType)
if (!view) {
panel.dispose()
return
}
this.wirePanel(panel, view, this.getProjectDirectory())
}
private wirePanel(panel: vscode.WebviewPanel, view: PanelView, projectDirectory: string | null): void {
panel.iconPath = {
light: vscode.Uri.joinPath(this.extensionUri, "assets", "icons", "kilo-light.svg"),
dark: vscode.Uri.joinPath(this.extensionUri, "assets", "icons", "kilo-dark.svg"),
@@ -105,6 +131,7 @@ export class SettingsEditorProvider implements vscode.Disposable {
this.panels.set(view, panel)
this.providers.set(view, provider)
const title = PANEL_TITLES[view]
panel.onDidDispose(() => {
console.log(`[Kilo New] ${title} panel disposed`)
closePanelDisposable.dispose()
+52
View File
@@ -66,6 +66,25 @@ export function activate(context: vscode.ExtensionContext) {
}),
)
// Register serializer so "Open in Tab" restores when VS Code restarts
context.subscriptions.push(
vscode.window.registerWebviewPanelSerializer("kilo-code.new.TabPanel", {
deserializeWebviewPanel(panel: vscode.WebviewPanel) {
const tabProvider = new KiloProvider(context.extensionUri, connectionService, context)
tabProvider.resolveWebviewPanel(panel)
panel.onDidDispose(
() => {
console.log("[Kilo New] Tab panel restored from restart disposed")
tabProvider.dispose()
},
null,
context.subscriptions,
)
return Promise.resolve()
},
}),
)
// Create standalone diff viewer provider for the sidebar "Show Changes" action
const diffViewerProvider = new DiffViewerProvider(context.extensionUri, connectionService)
diffViewerProvider.setCommentHandler((comments) => {
@@ -81,6 +100,39 @@ export function activate(context: vscode.ExtensionContext) {
const subAgentViewerProvider = new SubAgentViewerProvider(context.extensionUri, connectionService, context)
context.subscriptions.push(subAgentViewerProvider)
// Register serializers so settings/diff/sub-agent panels restore on restart
const settingsViews = ["settingsPanel", "profilePanel", "marketplacePanel"] as const
for (const suffix of settingsViews) {
context.subscriptions.push(
vscode.window.registerWebviewPanelSerializer(`kilo-code.new.${suffix}`, {
deserializeWebviewPanel(panel: vscode.WebviewPanel) {
settingsEditorProvider.deserializePanel(panel)
return Promise.resolve()
},
}),
)
}
context.subscriptions.push(
vscode.window.registerWebviewPanelSerializer(DiffViewerProvider.viewType, {
deserializeWebviewPanel(panel: vscode.WebviewPanel) {
diffViewerProvider.deserializePanel(panel)
return Promise.resolve()
},
}),
)
context.subscriptions.push(
vscode.window.registerWebviewPanelSerializer("kilo-code.new.SubAgentViewerPanel", {
deserializeWebviewPanel(panel: vscode.WebviewPanel) {
// Sub-agent viewer requires a session ID that can't be recovered
// after restart, so dispose the stale panel cleanly.
panel.dispose()
return Promise.resolve()
},
}),
)
// Register toolbar button command handlers
context.subscriptions.push(
vscode.commands.registerCommand("kilo-code.new.plusButtonClicked", () => {