11import { useAtomValue } from "@effect/atom-react" ;
2+ import { useSyncExternalStore } from "react" ;
23import type { EnvironmentId , PreviewRuntime , PreviewSessionSnapshot } from "@t3tools/contracts" ;
34
45import { isElectron } from "~/env" ;
@@ -61,17 +62,47 @@ function desktopHostsServerTab(
6162 ) ;
6263}
6364
64- // Fixed when a tab first appears: moving a page between hosts would replace it.
65- const backgroundHostedTabs = new Map < string , boolean > ( ) ;
65+ // Fixed when a tab first appears, until T3 is on screen again: moving a page between hosts replaces it.
66+ let backgroundHostedTabs = new Map < string , boolean > ( ) ;
67+ const hostingListeners = new Set < ( ) => void > ( ) ;
68+
69+ // Its window takes focus when T3 is shown again. Background tabs then move to panel webviews, where
70+ // every desktop tool works, and a new map makes memoized callers look again.
71+ const returnBackgroundTabsToPanel = ( ) => {
72+ if ( ! [ ...backgroundHostedTabs . values ( ) ] . some ( Boolean ) ) return ;
73+ backgroundHostedTabs = new Map ( [ ...backgroundHostedTabs . keys ( ) ] . map ( ( key ) => [ key , false ] ) ) ;
74+ for ( const listener of hostingListeners ) listener ( ) ;
75+ } ;
76+
77+ const subscribeBackgroundHosting = ( listener : ( ) => void ) => {
78+ hostingListeners . add ( listener ) ;
79+ if ( hostingListeners . size === 1 ) window . addEventListener ( "focus" , returnBackgroundTabsToPanel ) ;
80+ return ( ) => {
81+ hostingListeners . delete ( listener ) ;
82+ if ( hostingListeners . size === 0 ) {
83+ window . removeEventListener ( "focus" , returnBackgroundTabsToPanel ) ;
84+ }
85+ } ;
86+ } ;
87+
88+ export type BackgroundHosting = ReadonlyMap < string , boolean > ;
89+
90+ export const readBackgroundHosting = ( ) : BackgroundHosting => backgroundHostedTabs ;
91+
92+ export function useBackgroundHosting ( ) : BackgroundHosting {
93+ return useSyncExternalStore ( subscribeBackgroundHosting , readBackgroundHosting ) ;
94+ }
6695
6796/**
6897 * A panel `<webview>` created while the app window is hidden or minimized never paints, so an
6998 * agent tab that appears then runs in a never-shown desktop window and the panel streams it.
99+ * `hosting` is the map from `useBackgroundHosting`, passed so memoized callers recompute.
70100 */
71101export function hostsServerTabInBackground (
72102 environmentId : EnvironmentId ,
73103 primaryEnvironmentId : EnvironmentId | null ,
74104 snapshot : RuntimeSnapshot | null | undefined ,
105+ hosting : BackgroundHosting ,
75106) : boolean {
76107 if (
77108 ! snapshot ||
@@ -81,28 +112,33 @@ export function hostsServerTabInBackground(
81112 return false ;
82113 }
83114 const key = `${ environmentId } \u0000${ snapshot . threadId } \u0000${ snapshot . tabId } ` ;
84- let background = backgroundHostedTabs . get ( key ) ;
85- if ( background === undefined ) {
86- background = window . desktopBridge ?. getWindowShown ?.( ) === false ;
87- backgroundHostedTabs . set ( key , background ) ;
88- }
115+ const decided = backgroundHostedTabs . get ( key ) ?? hosting . get ( key ) ;
116+ if ( decided !== undefined ) return decided ;
117+ const background = window . desktopBridge ?. getWindowShown ?.( ) === false ;
118+ backgroundHostedTabs . set ( key , background ) ;
89119 return background ;
90120}
91121
92122export function rendersServerTabNatively (
93123 environmentId : EnvironmentId ,
94124 primaryEnvironmentId : EnvironmentId | null ,
95125 snapshot : RuntimeSnapshot | null | undefined ,
126+ hosting : BackgroundHosting ,
96127) : boolean {
97128 return (
98129 desktopHostsServerTab ( environmentId , primaryEnvironmentId , snapshot ) &&
99- ! hostsServerTabInBackground ( environmentId , primaryEnvironmentId , snapshot )
130+ ! hostsServerTabInBackground ( environmentId , primaryEnvironmentId , snapshot , hosting )
100131 ) ;
101132}
102133
103134export function useRendersServerTabNatively (
104135 environmentId : EnvironmentId ,
105136 snapshot : RuntimeSnapshot | null | undefined ,
106137) : boolean {
107- return rendersServerTabNatively ( environmentId , useAtomValue ( primaryEnvironmentIdAtom ) , snapshot ) ;
138+ return rendersServerTabNatively (
139+ environmentId ,
140+ useAtomValue ( primaryEnvironmentIdAtom ) ,
141+ snapshot ,
142+ useBackgroundHosting ( ) ,
143+ ) ;
108144}
0 commit comments