diff --git a/src/renderer/src/store/slices/browser.test.ts b/src/renderer/src/store/slices/browser.test.ts index 61a534c6194..6a21013962b 100644 --- a/src/renderer/src/store/slices/browser.test.ts +++ b/src/renderer/src/store/slices/browser.test.ts @@ -658,6 +658,28 @@ describe('createBrowserSlice runtime guard', () => { ) }) + it('clears the deleted profile partition from referencing tabs so they fall back to the default partition', async () => { + // Regression for #6923 follow-up: deleting a profile de-allowlists its + // partition in main. A tab still pointing at it would be denied attachment + // by will-attach-webview and render blank after restart/remount. The tab + // must reset to the allowlisted default partition instead. + const store = createTestStore() + mockApi.browser.sessionDeleteProfile.mockResolvedValueOnce(true) + store.setState({ browserSessionProfiles: [] }) + const tab = store.getState().createBrowserTab('wt-1', 'https://example.com', { + sessionProfileId: 'profile-isolated', + sessionPartition: 'persist:orca-browser-session-profile-isolated' + }) + + await store.getState().deleteBrowserSessionProfile('profile-isolated') + + const updated = store + .getState() + .browserTabsByWorktree['wt-1']?.find((t) => t.id === tab.id) + expect(updated?.sessionProfileId).toBeNull() + expect(updated?.sessionPartition).toBeNull() + }) + it('creates new browser tabs through the owning runtime for desktop remote worktrees', async () => { const store = createTestStore() store.setState({ diff --git a/src/renderer/src/store/slices/browser.ts b/src/renderer/src/store/slices/browser.ts index 53d07f58127..3831e9c20e7 100644 --- a/src/renderer/src/store/slices/browser.ts +++ b/src/renderer/src/store/slices/browser.ts @@ -349,6 +349,33 @@ function buildWorkspaceFromPage( } } +// Why: when a session profile is deleted its per-profile partition is removed +// from the main-process allowlist, so any tab still pointing at it would be +// denied attachment by will-attach-webview and render blank after a restart or +// remount (#6923 follow-up). Reset the persisted profile id/partition on those +// tabs so the webview falls back to the allowlisted default partition, matching +// the pre-sessionPartition behavior. +function clearDeletedProfileFromBrowserTabs( + browserTabsByWorktree: Record, + profileId: string +): Record { + let changed = false + const next: Record = {} + for (const [worktreeId, tabs] of Object.entries(browserTabsByWorktree)) { + let tabsChanged = false + const updatedTabs = tabs.map((tab) => { + if (tab.sessionProfileId !== profileId) { + return tab + } + tabsChanged = true + return { ...tab, sessionProfileId: null, sessionPartition: null } + }) + next[worktreeId] = tabsChanged ? updatedTabs : tabs + changed = changed || tabsChanged + } + return changed ? next : browserTabsByWorktree +} + function mirrorWorkspaceFromActivePage( workspace: BrowserWorkspace, pages: BrowserPage[] @@ -1791,6 +1818,10 @@ export const createBrowserSlice: StateCreator = s, s.browserSessionProfiles.filter((p) => p.id !== profileId) ), + browserTabsByWorktree: clearDeletedProfileFromBrowserTabs( + s.browserTabsByWorktree, + profileId + ), ...(s.defaultBrowserSessionProfileId === profileId ? { defaultBrowserSessionProfileId: null, @@ -1815,6 +1846,10 @@ export const createBrowserSlice: StateCreator = s, s.browserSessionProfiles.filter((p) => p.id !== profileId) ), + browserTabsByWorktree: clearDeletedProfileFromBrowserTabs( + s.browserTabsByWorktree, + profileId + ), ...(s.defaultBrowserSessionProfileId === profileId ? { defaultBrowserSessionProfileId: null,