@@ -121,22 +121,36 @@ function formatContextWindow(value: number | undefined, t: TFn): string | null {
121121 : t ( "claudeDesktop.contextK" , { n : Math . round ( value / 1_000 ) } ) ;
122122}
123123
124- export default function ClaudeDesktop ( { apiBase } : { apiBase : string } ) {
124+ type CachedDesktop = { data : DesktopResponse ; profile : DesktopProfile } ;
125+
126+ function readDesktopCache ( cacheKey : string ) : CachedDesktop | null {
127+ return readSessionListCache < CachedDesktop > ( cacheKey ) ;
128+ }
129+
130+ function seedDesktop ( cacheKey : string ) {
131+ const cached = readDesktopCache ( cacheKey ) ;
132+ return {
133+ data : cached ?. data ?? null ,
134+ profile : cached ?. profile ?? null ,
135+ savedProfile : cached ?. profile ? cloneProfile ( cached . profile ) : null ,
136+ destinations : cached ?. data
137+ ? Object . fromEntries (
138+ cached . data . models . map ( model => [ model . route , cached . profile . assignments [ model . route ] ?. family ?? "opus" ] ) ,
139+ )
140+ : { } as Record < string , Family > ,
141+ hasCache : Boolean ( cached ?. data ) ,
142+ } ;
143+ }
144+
145+ export default function ClaudeDesktop ( { apiBase, active = true } : { apiBase : string ; active ?: boolean } ) {
125146 const t = useT ( ) ;
126147 const cacheKey = `ocx.claude-desktop.v1:${ apiBase } ` ;
127- const cached = readSessionListCache < { data : DesktopResponse ; profile : DesktopProfile } > ( cacheKey ) ;
148+ const [ data , setData ] = useState < DesktopResponse | null > ( ( ) => seedDesktop ( cacheKey ) . data ) ;
149+ const [ profile , setProfile ] = useState < DesktopProfile | null > ( ( ) => seedDesktop ( cacheKey ) . profile ) ;
150+ const [ savedProfile , setSavedProfile ] = useState < DesktopProfile | null > ( ( ) => seedDesktop ( cacheKey ) . savedProfile ) ;
151+ const [ destinations , setDestinations ] = useState < Record < string , Family > > ( ( ) => seedDesktop ( cacheKey ) . destinations ) ;
128152 const [ status , setStatus ] = useState < DesktopStatus | null > ( null ) ;
129- const [ data , setData ] = useState < DesktopResponse | null > ( ( ) => cached ?. data ?? null ) ;
130- const [ profile , setProfile ] = useState < DesktopProfile | null > ( ( ) => cached ?. profile ?? null ) ;
131- const [ savedProfile , setSavedProfile ] = useState < DesktopProfile | null > ( ( ) => (
132- cached ?. profile ? cloneProfile ( cached . profile ) : null
133- ) ) ;
134- const [ destinations , setDestinations ] = useState < Record < string , Family > > ( ( ) => (
135- cached ?. data
136- ? Object . fromEntries ( cached . data . models . map ( model => [ model . route , cached . profile . assignments [ model . route ] ?. family ?? "opus" ] ) )
137- : { }
138- ) ) ;
139- const [ loading , setLoading ] = useState ( ( ) => ! cached ?. data ) ;
153+ const [ loading , setLoading ] = useState ( ( ) => ! seedDesktop ( cacheKey ) . hasCache ) ;
140154 const [ loadError , setLoadError ] = useState ( "" ) ;
141155 const [ message , setMessage ] = useState < { tone : "ok" | "err" ; text : string } | null > ( null ) ;
142156 const [ announcement , setAnnouncement ] = useState ( "" ) ;
@@ -155,7 +169,7 @@ export default function ClaudeDesktop({ apiBase }: { apiBase: string }) {
155169 // is not, and restoring five open rows on reload would rebuild the wall this removes.
156170 const [ openRows , setOpenRows ] = useState < Record < string , boolean > > ( { } ) ;
157171 const importRef = useRef < HTMLInputElement > ( null ) ;
158- const hasCacheRef = useRef ( Boolean ( cached ?. data ) ) ;
172+ const hasCacheRef = useRef ( seedDesktop ( cacheKey ) . hasCache ) ;
159173
160174 const load = useCallback ( async ( ) => {
161175 if ( ! hasCacheRef . current ) setLoading ( true ) ;
@@ -220,16 +234,17 @@ export default function ClaudeDesktop({ apiBase }: { apiBase: string }) {
220234 return result ;
221235 } , [ modelsByFamily , profile ] ) ;
222236
223- // Poll Desktop status every 5s for applied-state + health.
237+ // Poll Desktop status every 5s for applied-state + health (paused while tab is hidden) .
224238 useEffect ( ( ) => {
239+ if ( ! active ) return ;
225240 let cancelled = false ;
226241 let inFlight = false ;
227- let active : ReturnType < typeof createBoundedFetch > | null = null ;
242+ let activeFetch : ReturnType < typeof createBoundedFetch > | null = null ;
228243 const poll = ( ) => {
229244 if ( inFlight ) return ;
230245 inFlight = true ;
231246 const bounded = createBoundedFetch ( 10_000 ) ;
232- active = bounded ;
247+ activeFetch = bounded ;
233248 void fetch ( `${ apiBase } /api/claude-desktop/status` , { signal : bounded . signal } )
234249 . then ( ( response ) => readJsonIfOk < DesktopStatus > ( response ) )
235250 . then ( ( data ) => {
@@ -239,7 +254,7 @@ export default function ClaudeDesktop({ apiBase }: { apiBase: string }) {
239254 . catch ( ( ) => { /* offline / older proxy / aborted */ } )
240255 . finally ( ( ) => {
241256 bounded . clear ( ) ;
242- if ( active === bounded ) active = null ;
257+ if ( activeFetch === bounded ) activeFetch = null ;
243258 inFlight = false ;
244259 } ) ;
245260 } ;
@@ -248,10 +263,10 @@ export default function ClaudeDesktop({ apiBase }: { apiBase: string }) {
248263 return ( ) => {
249264 cancelled = true ;
250265 clearInterval ( timer ) ;
251- active ?. controller . abort ( ) ;
252- active ?. clear ( ) ;
266+ activeFetch ?. controller . abort ( ) ;
267+ activeFetch ?. clear ( ) ;
253268 } ;
254- } , [ apiBase ] ) ;
269+ } , [ apiBase , active ] ) ;
255270
256271 const moveModel = ( route : string , family : Family ) => {
257272 if ( ! profile || profile . assignments [ route ] ?. family === family ) return ;
0 commit comments