mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-08-29 03:44:06 +08:00
refactor: revert hotreload
This commit is contained in:
@@ -23,13 +23,10 @@ export class KiloProvider implements vscode.WebviewViewProvider {
|
||||
private unsubscribeEvent: (() => void) | null = null
|
||||
private unsubscribeState: (() => void) | null = null
|
||||
private webviewMessageDisposable: vscode.Disposable | null = null
|
||||
private webviewWatcherDisposable: vscode.Disposable | null = null
|
||||
private debounceTimer: NodeJS.Timeout | null = null
|
||||
|
||||
constructor(
|
||||
private readonly extensionUri: vscode.Uri,
|
||||
private readonly connectionService: KiloConnectionService,
|
||||
private readonly context: vscode.ExtensionContext,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -118,9 +115,6 @@ export class KiloProvider implements vscode.WebviewViewProvider {
|
||||
// Handle messages from webview (shared handler)
|
||||
this.setupWebviewMessageHandler(webviewView.webview)
|
||||
|
||||
// Set up hot reload watcher for development mode
|
||||
this.setupWebviewHotReload(webviewView.webview)
|
||||
|
||||
// Initialize connection to CLI backend
|
||||
this.initializeConnection()
|
||||
}
|
||||
@@ -143,9 +137,6 @@ export class KiloProvider implements vscode.WebviewViewProvider {
|
||||
// Handle messages from webview (shared handler)
|
||||
this.setupWebviewMessageHandler(panel.webview)
|
||||
|
||||
// Set up hot reload watcher for development mode
|
||||
this.setupWebviewHotReload(panel.webview)
|
||||
|
||||
this.initializeConnection()
|
||||
}
|
||||
|
||||
@@ -292,67 +283,6 @@ export class KiloProvider implements vscode.WebviewViewProvider {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up hot reload watcher for webview in development mode.
|
||||
* Watches CSS and JS files separately for optimal hot-swapping.
|
||||
* - CSS: instant hot-swap with no state loss
|
||||
* - JS: state-preserving reload via getState/setState
|
||||
*/
|
||||
private setupWebviewHotReload(webview: vscode.Webview): void {
|
||||
// Only enable in development mode
|
||||
if (this.context.extensionMode !== vscode.ExtensionMode.Development) {
|
||||
return
|
||||
}
|
||||
|
||||
// Clean up existing watcher if any
|
||||
this.webviewWatcherDisposable?.dispose()
|
||||
this.debounceTimer && clearTimeout(this.debounceTimer)
|
||||
|
||||
// Watch CSS files for instant hot-swap
|
||||
const cssWatcher = vscode.workspace.createFileSystemWatcher(
|
||||
new vscode.RelativePattern(this.extensionUri, "dist/webview.css"),
|
||||
)
|
||||
|
||||
const reloadCSS = () => {
|
||||
console.log("[Kilo New] KiloProvider: 🎨 Hot-swapping CSS (dev mode)")
|
||||
const styleUri = webview.asWebviewUri(vscode.Uri.joinPath(this.extensionUri, "dist", "webview.css")).toString()
|
||||
const cacheBusted = `${styleUri}?t=${Date.now()}`
|
||||
this.postMessage({
|
||||
type: "hotReloadCSS",
|
||||
href: cacheBusted,
|
||||
})
|
||||
}
|
||||
|
||||
cssWatcher.onDidChange(reloadCSS)
|
||||
cssWatcher.onDidCreate(reloadCSS)
|
||||
|
||||
// Watch JS files for state-preserving reload
|
||||
const jsWatcher = vscode.workspace.createFileSystemWatcher(
|
||||
new vscode.RelativePattern(this.extensionUri, "dist/webview.js"),
|
||||
)
|
||||
|
||||
const reloadJS = () => {
|
||||
// Clear any pending reload
|
||||
if (this.debounceTimer) {
|
||||
clearTimeout(this.debounceTimer)
|
||||
}
|
||||
|
||||
// Debounce JS reloads by 300ms to avoid multiple rapid reloads
|
||||
this.debounceTimer = setTimeout(() => {
|
||||
console.log("[Kilo New] KiloProvider: 🔄 Hot reloading JS with state preservation (dev mode)")
|
||||
this.postMessage({
|
||||
type: "hotReloadJS",
|
||||
})
|
||||
this.debounceTimer = null
|
||||
}, 300)
|
||||
}
|
||||
|
||||
jsWatcher.onDidChange(reloadJS)
|
||||
jsWatcher.onDidCreate(reloadJS)
|
||||
|
||||
this.webviewWatcherDisposable = vscode.Disposable.from(cssWatcher, jsWatcher)
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize connection to the CLI backend server.
|
||||
* Subscribes to the shared KiloConnectionService.
|
||||
@@ -1340,7 +1270,6 @@ export class KiloProvider implements vscode.WebviewViewProvider {
|
||||
const iconsBaseUri = webview.asWebviewUri(vscode.Uri.joinPath(this.extensionUri, "assets", "icons"))
|
||||
|
||||
const nonce = getNonce()
|
||||
const isDev = this.context.extensionMode === vscode.ExtensionMode.Development
|
||||
|
||||
// CSP allows:
|
||||
// - default-src 'none': Block everything by default
|
||||
@@ -1357,9 +1286,6 @@ export class KiloProvider implements vscode.WebviewViewProvider {
|
||||
`img-src ${webview.cspSource} data: https:`,
|
||||
].join("; ")
|
||||
|
||||
// No inline hot reload script - everything handled in the main app (index.tsx)
|
||||
const hotReloadScript = ""
|
||||
|
||||
return `<!DOCTYPE html>
|
||||
<html lang="en" data-theme="kilo-vscode">
|
||||
<head>
|
||||
@@ -1367,7 +1293,7 @@ export class KiloProvider implements vscode.WebviewViewProvider {
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="Content-Security-Policy" content="${csp}">
|
||||
<title>Kilo Code</title>
|
||||
<link id="kilo-stylesheet" rel="stylesheet" href="${styleUri}">
|
||||
<link rel="stylesheet" href="${styleUri}">
|
||||
<style>
|
||||
html, body {
|
||||
margin: 0;
|
||||
@@ -1393,7 +1319,7 @@ export class KiloProvider implements vscode.WebviewViewProvider {
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script nonce="${nonce}">window.ICONS_BASE_URI = "${iconsBaseUri}";</script>${hotReloadScript}
|
||||
<script nonce="${nonce}">window.ICONS_BASE_URI = "${iconsBaseUri}";</script>
|
||||
<script nonce="${nonce}" src="${scriptUri}"></script>
|
||||
</body>
|
||||
</html>`
|
||||
@@ -1407,11 +1333,6 @@ export class KiloProvider implements vscode.WebviewViewProvider {
|
||||
this.unsubscribeEvent?.()
|
||||
this.unsubscribeState?.()
|
||||
this.webviewMessageDisposable?.dispose()
|
||||
this.webviewWatcherDisposable?.dispose()
|
||||
if (this.debounceTimer) {
|
||||
clearTimeout(this.debounceTimer)
|
||||
this.debounceTimer = null
|
||||
}
|
||||
this.trackedSessionIds.clear()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import * as vscode from "vscode"
|
||||
import * as fs from "fs"
|
||||
import * as path from "path"
|
||||
import { KiloProvider } from "./KiloProvider"
|
||||
import { AgentManagerProvider } from "./AgentManagerProvider"
|
||||
import { EXTENSION_DISPLAY_NAME } from "./constants"
|
||||
@@ -11,24 +9,6 @@ import { BrowserAutomationService } from "./services/browser-automation"
|
||||
export function activate(context: vscode.ExtensionContext) {
|
||||
console.log("Kilo Code extension is now active")
|
||||
|
||||
// kilocode_change - ensure VS Code directories exist to prevent ENOENT errors during webview hot reload
|
||||
// VS Code 1.109+ checks for these directories during webview initialization
|
||||
try {
|
||||
const userConfigPath = path.join(context.globalStorageUri.fsPath, "..", "..", "..", "User")
|
||||
fs.mkdirSync(path.join(userConfigPath, "prompts"), { recursive: true })
|
||||
|
||||
// Also create .github/agents in workspace roots to prevent workspace-specific ENOENT
|
||||
const workspaceFolders = vscode.workspace.workspaceFolders
|
||||
if (workspaceFolders) {
|
||||
for (const folder of workspaceFolders) {
|
||||
const agentsPath = path.join(folder.uri.fsPath, ".github", "agents")
|
||||
fs.mkdirSync(agentsPath, { recursive: true })
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// Ignore errors (e.g., permissions, already exists)
|
||||
}
|
||||
|
||||
// Create shared connection service (one server for all webviews)
|
||||
const connectionService = new KiloConnectionService(context)
|
||||
|
||||
@@ -44,7 +24,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
})
|
||||
|
||||
// Create the provider with shared service
|
||||
const provider = new KiloProvider(context.extensionUri, connectionService, context)
|
||||
const provider = new KiloProvider(context.extensionUri, connectionService)
|
||||
|
||||
// Register the webview view provider for the sidebar
|
||||
context.subscriptions.push(vscode.window.registerWebviewViewProvider(KiloProvider.viewType, provider))
|
||||
@@ -115,7 +95,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, context)
|
||||
const tabProvider = new KiloProvider(context.extensionUri, connectionService)
|
||||
tabProvider.resolveWebviewPanel(panel)
|
||||
|
||||
// Wait for the new panel to become active before locking the editor group.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, createSignal, createMemo, createEffect, Switch, Match, onMount, onCleanup } from "solid-js"
|
||||
import { Component, createSignal, createMemo, Switch, Match, onMount, onCleanup } from "solid-js"
|
||||
import { ThemeProvider } from "@kilocode/kilo-ui/theme"
|
||||
import { DialogProvider } from "@kilocode/kilo-ui/context/dialog"
|
||||
import { MarkedProvider } from "@kilocode/kilo-ui/context/marked"
|
||||
@@ -6,7 +6,7 @@ import { DataProvider } from "@kilocode/kilo-ui/context/data"
|
||||
import { Toast } from "@kilocode/kilo-ui/toast"
|
||||
import Settings from "./components/Settings"
|
||||
import ProfileView from "./components/ProfileView"
|
||||
import { VSCodeProvider, useVSCode } from "./context/vscode"
|
||||
import { VSCodeProvider } from "./context/vscode"
|
||||
import { ServerProvider, useServer } from "./context/server"
|
||||
import { ProviderProvider } from "./context/provider"
|
||||
import { ConfigProvider } from "./context/config"
|
||||
@@ -15,7 +15,6 @@ import { LanguageProvider } from "./context/language"
|
||||
import { ChatView } from "./components/chat"
|
||||
import SessionList from "./components/history/SessionList"
|
||||
import type { Message as SDKMessage, Part as SDKPart } from "@kilocode/sdk/v2"
|
||||
import { restoreHotReloadState } from "./utils/hot-reload"
|
||||
import "./styles/chat.css"
|
||||
|
||||
type ViewType = "newTask" | "marketplace" | "history" | "profile" | "settings"
|
||||
@@ -92,25 +91,6 @@ const AppContent: Component = () => {
|
||||
const [currentView, setCurrentView] = createSignal<ViewType>("newTask")
|
||||
const session = useSession()
|
||||
const server = useServer()
|
||||
const vscode = useVSCode()
|
||||
|
||||
// Restore view from hot reload state
|
||||
onMount(() => {
|
||||
const restored = restoreHotReloadState(vscode)
|
||||
if (restored?.currentView && VALID_VIEWS.has(restored.currentView)) {
|
||||
console.log("[Kilo HMR] 🔄 Restored view:", restored.currentView)
|
||||
setCurrentView(restored.currentView as ViewType)
|
||||
}
|
||||
})
|
||||
|
||||
// Expose state getter for hot reload (called by inline script before reload)
|
||||
createEffect(() => {
|
||||
;(window as any).__getHotReloadState = () => ({
|
||||
currentView: currentView(),
|
||||
currentSessionID: session.currentSessionID(),
|
||||
selectedAgent: session.selectedAgent(),
|
||||
})
|
||||
})
|
||||
|
||||
const handleViewAction = (action: string) => {
|
||||
switch (action) {
|
||||
@@ -183,36 +163,30 @@ const AppContent: Component = () => {
|
||||
|
||||
// Main App component with context providers
|
||||
const App: Component = () => {
|
||||
console.log("[Kilo Debug] App component rendering")
|
||||
try {
|
||||
return (
|
||||
<ThemeProvider defaultTheme="kilo-vscode">
|
||||
<DialogProvider>
|
||||
<VSCodeProvider>
|
||||
<ServerProvider>
|
||||
<LanguageBridge>
|
||||
<MarkedProvider>
|
||||
<ProviderProvider>
|
||||
<ConfigProvider>
|
||||
<SessionProvider>
|
||||
<DataBridge>
|
||||
<AppContent />
|
||||
</DataBridge>
|
||||
</SessionProvider>
|
||||
</ConfigProvider>
|
||||
</ProviderProvider>
|
||||
</MarkedProvider>
|
||||
</LanguageBridge>
|
||||
</ServerProvider>
|
||||
</VSCodeProvider>
|
||||
<Toast.Region />
|
||||
</DialogProvider>
|
||||
</ThemeProvider>
|
||||
)
|
||||
} catch (error) {
|
||||
console.error("[Kilo Debug] Error in App component:", error)
|
||||
throw error
|
||||
}
|
||||
return (
|
||||
<ThemeProvider defaultTheme="kilo-vscode">
|
||||
<DialogProvider>
|
||||
<VSCodeProvider>
|
||||
<ServerProvider>
|
||||
<LanguageBridge>
|
||||
<MarkedProvider>
|
||||
<ProviderProvider>
|
||||
<ConfigProvider>
|
||||
<SessionProvider>
|
||||
<DataBridge>
|
||||
<AppContent />
|
||||
</DataBridge>
|
||||
</SessionProvider>
|
||||
</ConfigProvider>
|
||||
</ProviderProvider>
|
||||
</MarkedProvider>
|
||||
</LanguageBridge>
|
||||
</ServerProvider>
|
||||
</VSCodeProvider>
|
||||
<Toast.Region />
|
||||
</DialogProvider>
|
||||
</ThemeProvider>
|
||||
)
|
||||
}
|
||||
|
||||
export default App
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Text input with send/abort buttons and ghost-text autocomplete for the chat interface
|
||||
*/
|
||||
|
||||
import { Component, createSignal, createEffect, onMount, onCleanup, Show } from "solid-js"
|
||||
import { Component, createSignal, onCleanup, Show } from "solid-js"
|
||||
import { Button } from "@kilocode/kilo-ui/button"
|
||||
import { Tooltip } from "@kilocode/kilo-ui/tooltip"
|
||||
import { useSession } from "../../context/session"
|
||||
@@ -12,7 +12,6 @@ import { useLanguage } from "../../context/language"
|
||||
import { useVSCode } from "../../context/vscode"
|
||||
import { ModelSelector } from "./ModelSelector"
|
||||
import { ModeSwitcher } from "./ModeSwitcher"
|
||||
import { restoreHotReloadState } from "../../utils/hot-reload"
|
||||
|
||||
const AUTOCOMPLETE_DEBOUNCE_MS = 500
|
||||
const MIN_TEXT_LENGTH = 3
|
||||
@@ -33,23 +32,6 @@ export const PromptInput: Component = () => {
|
||||
const isDisabled = () => !server.isConnected()
|
||||
const canSend = () => text().trim().length > 0 && !isBusy() && !isDisabled()
|
||||
|
||||
// Restore input text from hot reload
|
||||
onMount(() => {
|
||||
const restored = restoreHotReloadState(vscode)
|
||||
if (restored?.inputText) {
|
||||
console.log("[Kilo HMR] 🔄 Restoring input text")
|
||||
setText(restored.inputText)
|
||||
if (textareaRef) {
|
||||
textareaRef.value = restored.inputText
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Expose text getter for hot reload (called by inline script before reload)
|
||||
createEffect(() => {
|
||||
;(window as any).__getPromptInputText = () => text()
|
||||
})
|
||||
|
||||
// Listen for chat completion results from the extension
|
||||
const unsubscribe = vscode.onMessage((message) => {
|
||||
if (message.type === "chatCompletionResult") {
|
||||
|
||||
@@ -20,7 +20,6 @@ import { createStore, produce } from "solid-js/store"
|
||||
import { useVSCode } from "./vscode"
|
||||
import { useServer } from "./server"
|
||||
import { useProvider } from "./provider"
|
||||
import { restoreHotReloadState } from "../utils/hot-reload"
|
||||
import type {
|
||||
SessionInfo,
|
||||
Message,
|
||||
@@ -144,23 +143,6 @@ export const SessionProvider: ParentComponent = (props) => {
|
||||
modelSelections: {},
|
||||
})
|
||||
|
||||
// Restore state from hot reload
|
||||
onMount(() => {
|
||||
const restored = restoreHotReloadState(vscode)
|
||||
if (restored) {
|
||||
if (restored.currentSessionID) {
|
||||
console.log("[Kilo HMR] 🔄 Restoring session:", restored.currentSessionID)
|
||||
setCurrentSessionID(restored.currentSessionID)
|
||||
// Request messages for the restored session
|
||||
vscode.postMessage({ type: "loadMessages", sessionID: restored.currentSessionID })
|
||||
}
|
||||
if (restored.selectedAgent) {
|
||||
console.log("[Kilo HMR] 🔄 Restoring agent:", restored.selectedAgent)
|
||||
setSelectedAgentName(restored.selectedAgent)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Keep pending selection in sync with provider default until the user
|
||||
// explicitly changes it (or a session exists).
|
||||
createEffect(() => {
|
||||
|
||||
@@ -38,51 +38,12 @@ interface VSCodeContextValue {
|
||||
const VSCodeContext = createContext<VSCodeContextValue>()
|
||||
|
||||
export const VSCodeProvider: ParentComponent = (props) => {
|
||||
console.log("[Kilo Debug] VSCodeProvider initializing")
|
||||
const api = getVSCodeAPI()
|
||||
console.log("[Kilo Debug] VSCodeProvider got API")
|
||||
const handlers = new Set<(message: ExtensionMessage) => void>()
|
||||
|
||||
// Listen for messages from the extension
|
||||
const messageListener = (event: MessageEvent) => {
|
||||
const message = event.data as ExtensionMessage
|
||||
|
||||
// Handle hot reload messages first (dev mode only)
|
||||
if (message?.type === "hotReloadCSS") {
|
||||
const link = document.getElementById("kilo-stylesheet") as HTMLLinkElement
|
||||
if (link) {
|
||||
console.log("[Kilo HMR] Swapping CSS")
|
||||
link.href = (message as any).href
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (message?.type === "hotReloadJS") {
|
||||
console.log("[Kilo HMR] Reloading with state preservation")
|
||||
|
||||
// Collect state from the app
|
||||
const appState = (window as any).__getHotReloadState ? (window as any).__getHotReloadState() : {}
|
||||
const inputText = (window as any).__getPromptInputText ? (window as any).__getPromptInputText() : ""
|
||||
|
||||
// Save current state before reload
|
||||
const state = (api.getState() || {}) as any
|
||||
state._hotReload = {
|
||||
timestamp: Date.now(),
|
||||
currentView: appState.currentView,
|
||||
currentSessionID: appState.currentSessionID,
|
||||
selectedAgent: appState.selectedAgent,
|
||||
inputText,
|
||||
}
|
||||
|
||||
api.setState(state)
|
||||
console.log("[Kilo HMR] Saved state:", state._hotReload)
|
||||
|
||||
// Reload the webview
|
||||
location.reload()
|
||||
return
|
||||
}
|
||||
|
||||
// Forward all other messages to handlers
|
||||
handlers.forEach((handler) => handler(message))
|
||||
}
|
||||
|
||||
@@ -105,7 +66,6 @@ export const VSCodeProvider: ParentComponent = (props) => {
|
||||
setState: <T,>(state: T) => api.setState(state),
|
||||
}
|
||||
|
||||
console.log("[Kilo Debug] VSCodeProvider rendering children")
|
||||
return <VSCodeContext.Provider value={value}>{props.children}</VSCodeContext.Provider>
|
||||
}
|
||||
|
||||
|
||||
@@ -1,28 +1,12 @@
|
||||
/* @refresh reload */
|
||||
console.log("[Kilo Debug] index.tsx loaded")
|
||||
|
||||
import "@kilocode/kilo-ui/styles"
|
||||
console.log("[Kilo Debug] styles imported")
|
||||
|
||||
import { render } from "solid-js/web"
|
||||
console.log("[Kilo Debug] solid-js/web imported")
|
||||
|
||||
import App from "./App"
|
||||
console.log("[Kilo Debug] App imported")
|
||||
|
||||
const root = document.getElementById("root")
|
||||
console.log("[Kilo Debug] root element:", root)
|
||||
|
||||
if (!root) {
|
||||
console.error("[Kilo Debug] Root element not found!")
|
||||
throw new Error("Root element not found")
|
||||
}
|
||||
|
||||
console.log("[Kilo Debug] About to render App")
|
||||
try {
|
||||
render(() => <App />, root)
|
||||
console.log("[Kilo Debug] App rendered successfully")
|
||||
} catch (error) {
|
||||
console.error("[Kilo Debug] Error rendering App:", error)
|
||||
throw error
|
||||
}
|
||||
render(() => <App />, root)
|
||||
|
||||
@@ -482,15 +482,6 @@ export interface NotificationSettingsLoadedMessage {
|
||||
}
|
||||
}
|
||||
|
||||
export interface HotReloadCSSMessage {
|
||||
type: "hotReloadCSS"
|
||||
href: string
|
||||
}
|
||||
|
||||
export interface HotReloadJSMessage {
|
||||
type: "hotReloadJS"
|
||||
}
|
||||
|
||||
export type ExtensionMessage =
|
||||
| ReadyMessage
|
||||
| ConnectionStateMessage
|
||||
@@ -523,8 +514,6 @@ export type ExtensionMessage =
|
||||
| ConfigLoadedMessage
|
||||
| ConfigUpdatedMessage
|
||||
| NotificationSettingsLoadedMessage
|
||||
| HotReloadCSSMessage
|
||||
| HotReloadJSMessage
|
||||
|
||||
// ============================================
|
||||
// Messages FROM webview TO extension
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
/**
|
||||
* Hot reload state management
|
||||
* Saves and restores critical UI state across JS reloads
|
||||
*/
|
||||
|
||||
import type { VSCodeAPI } from "../types/messages"
|
||||
|
||||
export interface HotReloadState {
|
||||
_hotReload?: {
|
||||
timestamp: number
|
||||
currentView?: string
|
||||
currentSessionID?: string
|
||||
inputText?: string
|
||||
scrollPosition?: number
|
||||
selectedProviderID?: string
|
||||
selectedModelID?: string
|
||||
selectedAgent?: string
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save current state before a hot reload
|
||||
*/
|
||||
export function saveHotReloadState(
|
||||
vscodeApi: VSCodeAPI,
|
||||
state: {
|
||||
currentView?: string
|
||||
currentSessionID?: string
|
||||
inputText?: string
|
||||
scrollPosition?: number
|
||||
selectedProviderID?: string
|
||||
selectedModelID?: string
|
||||
selectedAgent?: string
|
||||
},
|
||||
): void {
|
||||
const existing = (vscodeApi.getState() || {}) as HotReloadState
|
||||
existing._hotReload = {
|
||||
timestamp: Date.now(),
|
||||
...state,
|
||||
}
|
||||
vscodeApi.setState(existing)
|
||||
console.log("[Kilo HMR] 💾 Saved state:", existing._hotReload)
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore state after a hot reload
|
||||
* Returns the saved state and clears it from storage
|
||||
*/
|
||||
export function restoreHotReloadState(vscodeApi: VSCodeAPI): HotReloadState["_hotReload"] | undefined {
|
||||
const state = (vscodeApi.getState() || {}) as HotReloadState
|
||||
const hotReloadState = state._hotReload
|
||||
|
||||
if (hotReloadState) {
|
||||
// Check if the reload happened within the last 5 seconds
|
||||
const age = Date.now() - hotReloadState.timestamp
|
||||
if (age < 5000) {
|
||||
console.log("[Kilo HMR] 📦 Restored state:", hotReloadState)
|
||||
// Clear the hot reload state after restoring
|
||||
delete state._hotReload
|
||||
vscodeApi.setState(state)
|
||||
return hotReloadState
|
||||
}
|
||||
console.log("[Kilo HMR] ⏰ Hot reload state expired (age: ${age}ms)")
|
||||
}
|
||||
|
||||
return undefined
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this is a hot reload (vs initial load)
|
||||
*/
|
||||
export function isHotReload(vscodeApi: VSCodeAPI): boolean {
|
||||
const state = (vscodeApi.getState() || {}) as HotReloadState
|
||||
return !!state._hotReload
|
||||
}
|
||||
Reference in New Issue
Block a user