@@ -633,8 +633,14 @@ function TokenCachePanel(props: {
633633 if ( props . api . kv . ready ) {
634634 doRestore ( )
635635 } else {
636+ // Poll kv.ready with a 1-second timeout to avoid infinite busy-wait
637+ // on platforms where kv initialisation may be delayed (Linux single-thread
638+ // mode, session switch storms, etc.).
639+ const MAX_POLL = 100
640+ let tries = 0
636641 const pollRestore = ( ) => {
637642 if ( ! props . api . kv . ready ) {
643+ if ( ++ tries > MAX_POLL ) { doRestore ( ) ; return }
638644 setTimeout ( pollRestore , 10 )
639645 return
640646 }
@@ -643,13 +649,17 @@ function TokenCachePanel(props: {
643649 pollRestore ( )
644650 }
645651
646- const unsubPart = props . api . event . on ( "message.part.updated" , ( ) => {
647- setPartVersion ( ( v ) => v + 1 )
648- } )
649- const unsubMsg = props . api . event . on ( "message.updated" , ( ) => {
650- setPartVersion ( ( v ) => v + 1 )
651- } )
652- onCleanup ( ( ) => { unsubPart ( ) ; unsubMsg ( ) } )
652+ // Debounce partVersion updates so that event bursts during session
653+ // switching / streaming don't cause data() to re-compute on every
654+ // single event (up to hundreds per second on Linux single-thread).
655+ let partTimer : ReturnType < typeof setTimeout > | undefined
656+ const bumpPartVersion = ( ) => {
657+ clearTimeout ( partTimer )
658+ partTimer = setTimeout ( ( ) => setPartVersion ( ( v ) => v + 1 ) , 100 )
659+ }
660+ const unsubPart = props . api . event . on ( "message.part.updated" , bumpPartVersion )
661+ const unsubMsg = props . api . event . on ( "message.updated" , bumpPartVersion )
662+ onCleanup ( ( ) => { clearTimeout ( partTimer ) ; unsubPart ( ) ; unsubMsg ( ) } )
653663 } )
654664
655665 // ── colours ──
0 commit comments