diff --git a/packages/app/e2e/performance/timeline/timeline-test-helpers.ts b/packages/app/e2e/performance/timeline/timeline-test-helpers.ts index 401fb74496..6360b4a793 100644 --- a/packages/app/e2e/performance/timeline/timeline-test-helpers.ts +++ b/packages/app/e2e/performance/timeline/timeline-test-helpers.ts @@ -45,7 +45,7 @@ export async function installStressSessionTabs(page: Page, input?: { draftID?: s }), ) localStorage.setItem( - "opencode.global.dat:tabs", + "opencode.window.browser.dat:tabs", JSON.stringify([ ...sessionIDs.map((sessionId) => ({ type: "session", diff --git a/packages/app/e2e/regression/cross-server-tab-close.spec.ts b/packages/app/e2e/regression/cross-server-tab-close.spec.ts index 031440f166..159b5a5067 100644 --- a/packages/app/e2e/regression/cross-server-tab-close.spec.ts +++ b/packages/app/e2e/regression/cross-server-tab-close.spec.ts @@ -14,7 +14,7 @@ test("closing the active server's last tab opens the remaining server tab", asyn localStorage.setItem("settings.v3", JSON.stringify({ general: { newLayoutDesigns: true } })) localStorage.setItem("opencode.global.dat:server", JSON.stringify({ list: [serverB] })) localStorage.setItem( - "opencode.global.dat:tabs", + "opencode.window.browser.dat:tabs", JSON.stringify([ { type: "session", server: "http://127.0.0.1:4096", sessionId: sessionA }, { type: "session", server: serverB, sessionId: sessionB }, @@ -52,7 +52,7 @@ test("legacy session routes preserve an existing tab's server", async ({ page }) localStorage.setItem("settings.v3", JSON.stringify({ general: { newLayoutDesigns: true } })) localStorage.setItem("opencode.global.dat:server", JSON.stringify({ list: [serverB] })) localStorage.setItem( - "opencode.global.dat:tabs", + "opencode.window.browser.dat:tabs", JSON.stringify([{ type: "session", server: serverB, sessionId: sessionB }]), ) }, diff --git a/packages/app/e2e/regression/session-todo-dock-navigation.spec.ts b/packages/app/e2e/regression/session-todo-dock-navigation.spec.ts index fd0b00f71c..603c411d55 100644 --- a/packages/app/e2e/regression/session-todo-dock-navigation.spec.ts +++ b/packages/app/e2e/regression/session-todo-dock-navigation.spec.ts @@ -145,7 +145,7 @@ async function configurePage(page: Page) { }), ) localStorage.setItem( - "opencode.global.dat:tabs", + "opencode.window.browser.dat:tabs", JSON.stringify(sessionIDs.map((sessionId) => ({ type: "session", server, dirBase64, sessionId }))), ) }, diff --git a/packages/app/e2e/smoke/session-timeline.spec.ts b/packages/app/e2e/smoke/session-timeline.spec.ts index 5bca533e6a..a73cc0ccdd 100644 --- a/packages/app/e2e/smoke/session-timeline.spec.ts +++ b/packages/app/e2e/smoke/session-timeline.spec.ts @@ -127,7 +127,7 @@ test.describe("smoke: session timeline", () => { await page.addInitScript( ({ dirBase64, sourceID, targetID }) => { localStorage.setItem( - "opencode.global.dat:tabs", + "opencode.window.browser.dat:tabs", JSON.stringify( [sourceID, targetID].map((sessionId) => ({ type: "session", @@ -253,7 +253,7 @@ test.describe("smoke: session timeline", () => { await page.addInitScript( ({ dirBase64, sourceID, targetID }) => { localStorage.setItem( - "opencode.global.dat:tabs", + "opencode.window.browser.dat:tabs", JSON.stringify( [sourceID, targetID].map((sessionId) => ({ type: "session", diff --git a/packages/app/src/context/platform.tsx b/packages/app/src/context/platform.tsx index 0198b3b910..e59bec9aaf 100644 --- a/packages/app/src/context/platform.tsx +++ b/packages/app/src/context/platform.tsx @@ -67,9 +67,6 @@ type PlatformBase = { /** Stable platform window identity for window-scoped persistence */ windowID?: string - /** Whether window-scoped persistence should migrate legacy global values */ - migrateGlobalWindowState?: boolean - /** Application-global desktop updater */ updater?: UpdaterPlatform diff --git a/packages/app/src/utils/persist.test.ts b/packages/app/src/utils/persist.test.ts index 799cb80575..8e834f6116 100644 --- a/packages/app/src/utils/persist.test.ts +++ b/packages/app/src/utils/persist.test.ts @@ -210,13 +210,12 @@ describe("persist localStorage resilience", () => { expect(Persist.serverGlobal("a:b" as ServerScope, "c")).not.toEqual(Persist.serverGlobal("a" as ServerScope, "b:c")) }) - test("window target scopes browser storage and migrates global values", () => { + test("window target scopes browser storage", () => { const target = persistTesting.resolveTarget(Persist.window("tabs"), { platform: "web" } as ResolvePlatform) expect(target).toEqual({ scope: "window", storage: persistTesting.windowStorage("browser"), - legacyStorageNames: ["opencode.global.dat"], key: "tabs", legacy: undefined, }) @@ -226,13 +225,11 @@ describe("persist localStorage resilience", () => { const target = persistTesting.resolveTarget(Persist.window("tabs"), { platform: "desktop", windowID: "window-a", - migrateGlobalWindowState: false, } as ResolvePlatform) expect(target).toEqual({ scope: "window", storage: persistTesting.windowStorage("window-a"), - legacyStorageNames: undefined, key: "tabs", legacy: undefined, }) @@ -241,7 +238,6 @@ describe("persist localStorage resilience", () => { test("window target preserves global desktop storage without a window id", () => { const target = persistTesting.resolveTarget(Persist.window("tabs"), { platform: "desktop", - migrateGlobalWindowState: true, } as ResolvePlatform) expect(target).toEqual({ @@ -251,14 +247,4 @@ describe("persist localStorage resilience", () => { legacy: undefined, }) }) - - test("window target lets one desktop window migrate global values", () => { - const target = persistTesting.resolveTarget(Persist.window("tabs"), { - platform: "desktop", - windowID: "window-a", - migrateGlobalWindowState: true, - } as ResolvePlatform) - - expect(target.legacyStorageNames).toEqual(["opencode.global.dat"]) - }) }) diff --git a/packages/app/src/utils/persist.ts b/packages/app/src/utils/persist.ts index 12063664a9..671b798f61 100644 --- a/packages/app/src/utils/persist.ts +++ b/packages/app/src/utils/persist.ts @@ -519,11 +519,9 @@ function resolveTarget(target: PersistTarget, platform: Platform): PersistTarget if (target.scope !== "window") return target if (platform.platform === "desktop" && !platform.windowID) return { ...target, storage: GLOBAL_STORAGE } const windowID = platform.platform === "desktop" ? (platform.windowID ?? "browser") : "browser" - const shouldMigrate = platform.platform !== "desktop" || platform.migrateGlobalWindowState === true return { ...target, storage: windowStorage(windowID), - legacyStorageNames: shouldMigrate ? [GLOBAL_STORAGE, ...(target.legacyStorageNames ?? [])] : target.legacyStorageNames, } } diff --git a/packages/desktop/src/main/ipc.ts b/packages/desktop/src/main/ipc.ts index 30b427efca..32e314cb88 100644 --- a/packages/desktop/src/main/ipc.ts +++ b/packages/desktop/src/main/ipc.ts @@ -12,7 +12,6 @@ import { getStore } from "./store" import { getPinchZoomEnabled, getWindowID, - getWindowMigrateGlobalState, setPinchZoomEnabled, setTitlebar, updateTitlebar, @@ -205,12 +204,6 @@ export function registerIpcHandlers(deps: Deps) { return id }) - ipcMain.handle("get-window-migrate-global-state", (event: IpcMainInvokeEvent) => { - const win = BrowserWindow.fromWebContents(event.sender) - if (!win) return false - return getWindowMigrateGlobalState(win) - }) - ipcMain.handle("get-window-focused", (event: IpcMainInvokeEvent) => { const win = BrowserWindow.fromWebContents(event.sender) return win?.isFocused() ?? false diff --git a/packages/desktop/src/main/store-keys.ts b/packages/desktop/src/main/store-keys.ts index 0db09b2044..270ffe7504 100644 --- a/packages/desktop/src/main/store-keys.ts +++ b/packages/desktop/src/main/store-keys.ts @@ -3,4 +3,3 @@ export const DEFAULT_SERVER_URL_KEY = "defaultServerUrl" export const WSL_SERVERS_KEY = "wslServers" export const PINCH_ZOOM_ENABLED_KEY = "pinchZoomEnabled" export const WINDOW_IDS_KEY = "windowIds" -export const WINDOW_GLOBAL_STATE_MIGRATION_ID_KEY = "windowGlobalStateMigrationId" diff --git a/packages/desktop/src/main/windows.ts b/packages/desktop/src/main/windows.ts index 8eb3e621f5..b86ed156bf 100644 --- a/packages/desktop/src/main/windows.ts +++ b/packages/desktop/src/main/windows.ts @@ -9,7 +9,7 @@ import { fileURLToPath, pathToFileURL } from "node:url" import type { TitlebarTheme } from "../preload/types" import { exportDebugLogs, write as writeLog } from "./logging" import { getStore } from "./store" -import { PINCH_ZOOM_ENABLED_KEY, WINDOW_GLOBAL_STATE_MIGRATION_ID_KEY, WINDOW_IDS_KEY } from "./store-keys" +import { PINCH_ZOOM_ENABLED_KEY, WINDOW_IDS_KEY } from "./store-keys" import { createUnresponsiveSampler } from "./unresponsive" const root = dirname(fileURLToPath(import.meta.url)) @@ -45,7 +45,6 @@ let relaunchHandler = () => { } let appQuitting = false let lastFocusedWindowID: string | undefined -let windowGlobalStateMigrationID: string | undefined const titlebarThemes = new WeakMap>() const pinchZoomEnabled = new WeakMap() const windowIDs = new WeakMap() @@ -125,10 +124,6 @@ export function getWindowID(win: BrowserWindow) { return windowIDs.get(win) } -export function getWindowMigrateGlobalState(win: BrowserWindow) { - return getWindowID(win) === windowGlobalStateMigrationID -} - export function getLastFocusedWindow() { const focused = BrowserWindow.getFocusedWindow() if (focused) return focused @@ -140,9 +135,7 @@ export function getLastFocusedWindow() { export function restoreMainWindows() { const ids = readWindowIDs() - const next = ids.length ? ids : [randomUUID()] - windowGlobalStateMigrationID = readWindowGlobalStateMigrationID(next) - return next.map((id) => createMainWindow(id)) + return (ids.length ? ids : [randomUUID()]).map((id) => createMainWindow(id)) } export function setDockIcon() { @@ -252,14 +245,6 @@ function removeWindowID(id: string) { writeWindowIDs(readWindowIDs().filter((item) => item !== id)) } -function readWindowGlobalStateMigrationID(ids: string[]) { - const value = getStore().get(WINDOW_GLOBAL_STATE_MIGRATION_ID_KEY) - if (typeof value === "string" && ids.includes(value)) return value - const next = ids[0] - if (next) getStore().set(WINDOW_GLOBAL_STATE_MIGRATION_ID_KEY, next) - return next -} - export function registerRendererProtocol() { if (protocol.isProtocolHandled(rendererProtocol)) return diff --git a/packages/desktop/src/preload/index.ts b/packages/desktop/src/preload/index.ts index c83129d95a..f08a81c0d1 100644 --- a/packages/desktop/src/preload/index.ts +++ b/packages/desktop/src/preload/index.ts @@ -74,7 +74,6 @@ const api: ElectronAPI = { getWindowCount: () => ipcRenderer.invoke("get-window-count"), getWindowID: () => ipcRenderer.invoke("get-window-id"), - getWindowMigrateGlobalState: () => ipcRenderer.invoke("get-window-migrate-global-state"), onMenuCommand: (cb) => { const handler = (_: unknown, id: string) => cb(id) ipcRenderer.on("menu-command", handler) diff --git a/packages/desktop/src/preload/types.ts b/packages/desktop/src/preload/types.ts index 1ddb00ebe5..5401c2070d 100644 --- a/packages/desktop/src/preload/types.ts +++ b/packages/desktop/src/preload/types.ts @@ -63,7 +63,6 @@ export type ElectronAPI = { getWindowCount: () => Promise getWindowID: () => Promise - getWindowMigrateGlobalState: () => Promise onMenuCommand: (cb: (id: string) => void) => () => void onDeepLink: (cb: (urls: string[]) => void) => () => void diff --git a/packages/desktop/src/renderer/index.tsx b/packages/desktop/src/renderer/index.tsx index 8a70ed625f..febdec50ff 100644 --- a/packages/desktop/src/renderer/index.tsx +++ b/packages/desktop/src/renderer/index.tsx @@ -63,11 +63,9 @@ const [updaterState, setUpdaterState] = createSignal({ status: "di void window.api.updater.subscribe(setUpdaterState) const deepLinkEvent = "opencode:deep-link" -const lastActiveUrlKey = "opencode.desktop.last-active-url" type DesktopWindowState = { id?: string - migrateGlobalWindowState: boolean } const emitDeepLinks = (urls: string[]) => { @@ -87,12 +85,10 @@ function windowLastActiveUrlKey(windowID: string) { return `opencode.desktop.window.${windowID}.last-active-url` } -function getLastActiveUrl(windowID: string, migrateGlobalWindowState: boolean) { +function getLastActiveUrl(windowID: string) { if (typeof localStorage !== "object") return "/" try { - const value = - localStorage.getItem(windowLastActiveUrlKey(windowID)) ?? - (migrateGlobalWindowState ? localStorage.getItem(lastActiveUrlKey) : null) + const value = localStorage.getItem(windowLastActiveUrlKey(windowID)) if (value?.startsWith("/") && !value.startsWith("//")) return value } catch {} return "/" @@ -105,9 +101,9 @@ function setLastActiveUrl(windowID: string, value: string) { } catch {} } -function DesktopMemoryRouter(props: BaseRouterProps & { windowID: string; migrateGlobalWindowState: boolean }) { +function DesktopMemoryRouter(props: BaseRouterProps & { windowID: string }) { const history = createMemoryHistory() - const initialUrl = getLastActiveUrl(props.windowID, props.migrateGlobalWindowState) + const initialUrl = getLastActiveUrl(props.windowID) if (initialUrl !== "/") history.set({ value: initialUrl, replace: true, scroll: false }) onCleanup(history.listen((value) => setLastActiveUrl(props.windowID, value))) return @@ -173,7 +169,6 @@ const createPlatform = (windowState: DesktopWindowState): Platform => { os, version: pkg.version, windowID: windowState.id, - migrateGlobalWindowState: windowState.migrateGlobalWindowState, async openDirectoryPickerDialog(opts) { return window.api.openDirectoryPicker({ @@ -349,13 +344,7 @@ function DesktopRoot(props: { windowState: DesktopWindowState }) { const [defaultServer] = createResource(() => platform.getDefaultServer?.()) const [locale] = createResource(loadLocale) - const router = (props: BaseRouterProps) => ( - - ) + const router = (props: BaseRouterProps) => function handleClick(e: MouseEvent) { const link = (e.target as HTMLElement).closest("a.external-link") as HTMLAnchorElement | null @@ -443,13 +432,8 @@ render(() => { const [windowState] = createResource(async () => { const api = window.api as typeof window.api & { getWindowID?: () => Promise - getWindowMigrateGlobalState?: () => Promise - } - const id = await api.getWindowID?.() - return { - id, - migrateGlobalWindowState: id ? await (api.getWindowMigrateGlobalState?.() ?? false) : false, } + return { id: await api.getWindowID?.() } }) return (