@@ -8,7 +8,7 @@ import { Tooltip, TooltipContent, TooltipTrigger } from '@onlook/ui/tooltip';
88import { cn } from '@onlook/ui/utils' ;
99import { observer } from 'mobx-react-lite' ;
1010import { motion } from 'motion/react' ;
11- import { useEffect , useMemo , useRef , useState } from 'react' ;
11+ import { useEffect , useRef , useState } from 'react' ;
1212import { Terminal } from './terminal' ;
1313
1414export const TerminalArea = observer ( ( { children } : { children : React . ReactNode } ) => {
@@ -51,77 +51,75 @@ export const TerminalArea = observer(({ children }: { children: React.ReactNode
5151
5252 const [ terminalHidden , setTerminalHidden ] = useState ( true ) ;
5353 const [ restarting , setRestarting ] = useState ( false ) ;
54- const [ hasConnectionTimeout , setHasConnectionTimeout ] = useState ( false ) ;
55- const connectionStartTimeRef = useRef < number | null > ( null ) ;
54+
55+ // Ultra-lightweight error detection using a single timer
56+ const timeoutIdRef = useRef < NodeJS . Timeout | null > ( null ) ;
57+ const [ hasSandboxError , setHasSandboxError ] = useState ( false ) ;
5658
57- // Track connection state and detect timeouts (actual 502 errors)
59+ // Single effect that only sets/clears one timer - extremely efficient
5860 useEffect ( ( ) => {
61+ // Clear any existing timer first
62+ if ( timeoutIdRef . current ) {
63+ clearTimeout ( timeoutIdRef . current ) ;
64+ timeoutIdRef . current = null ;
65+ }
66+
5967 const activeBranch = branches . activeBranch ;
6068 if ( ! activeBranch ) {
61- setHasConnectionTimeout ( false ) ;
62- connectionStartTimeRef . current = null ;
69+ setHasSandboxError ( false ) ;
6370 return ;
6471 }
6572
6673 const branchData = branches . getBranchDataById ( activeBranch . id ) ;
67- const isConnecting = branchData ?. sandbox ?. session ?. isConnecting || branchData ?. sandbox ?. isIndexing ;
68- const hasProvider = branchData ?. sandbox ?. session ?. provider ;
69-
70- // If we have a provider, connection is successful - clear any timeout
71- if ( hasProvider ) {
72- setHasConnectionTimeout ( false ) ;
73- connectionStartTimeRef . current = null ;
74+ const sandbox = branchData ?. sandbox ;
75+
76+ // Quick bailouts - no timer needed
77+ if ( ! sandbox ?. session ) {
78+ setHasSandboxError ( false ) ;
7479 return ;
7580 }
76-
77- // If not connecting, clear the timeout tracking
78- if ( ! isConnecting ) {
79- setHasConnectionTimeout ( false ) ;
80- connectionStartTimeRef . current = null ;
81+
82+ // If we have a provider, we're connected - no error
83+ if ( sandbox . session . provider ) {
84+ setHasSandboxError ( false ) ;
8185 return ;
8286 }
83-
84- // Start tracking connection time if not already
85- if ( ! connectionStartTimeRef . current ) {
86- connectionStartTimeRef . current = Date . now ( ) ;
87+
88+ // Only set timer if actually connecting (not just idle)
89+ const isConnecting = sandbox . session . isConnecting || sandbox . isIndexing ;
90+ if ( ! isConnecting ) {
91+ setHasSandboxError ( false ) ;
92+ return ;
8793 }
8894
89- // Check if we've been connecting for too long (5 seconds - users see 502 quickly)
90- const connectionDuration = Date . now ( ) - connectionStartTimeRef . current ;
91- const TIMEOUT_MS = 5000 ; // 5 seconds - enough to avoid false positives but quick enough for 502s
92-
93- if ( connectionDuration >= TIMEOUT_MS ) {
94- // This is a real timeout/502 - show amber
95- setHasConnectionTimeout ( true ) ;
96- } else {
97- // Set up a timeout to check again
98- const remainingTime = TIMEOUT_MS - connectionDuration ;
99- const timeoutId = setTimeout ( ( ) => {
100- // Re-check if still connecting after timeout
101- const stillConnecting = branches . getBranchDataById ( activeBranch . id ) ?. sandbox ?. session ?. isConnecting ||
102- branches . getBranchDataById ( activeBranch . id ) ?. sandbox ?. isIndexing ;
103- const stillNoProvider = ! branches . getBranchDataById ( activeBranch . id ) ?. sandbox ?. session ?. provider ;
104-
105- if ( stillConnecting && stillNoProvider ) {
106- setHasConnectionTimeout ( true ) ;
107- }
108- } , remainingTime ) ;
109-
110- return ( ) => clearTimeout ( timeoutId ) ;
111- }
112- } , [ branches , branches . activeBranch ] ) ;
95+ // Set a single 5-second timer - that's it, ultra simple
96+ timeoutIdRef . current = setTimeout ( ( ) => {
97+ // Final check after 5 seconds
98+ const stillConnecting = branches . getBranchDataById ( activeBranch . id ) ?. sandbox ?. session ?. isConnecting ||
99+ branches . getBranchDataById ( activeBranch . id ) ?. sandbox ?. isIndexing ;
100+ const stillNoProvider = ! branches . getBranchDataById ( activeBranch . id ) ?. sandbox ?. session ?. provider ;
101+
102+ if ( stillConnecting && stillNoProvider ) {
103+ setHasSandboxError ( true ) ;
104+ }
105+ } , 5000 ) ;
113106
114- // Simple computed value - just check if we have a confirmed timeout
115- const hasSandboxError = hasConnectionTimeout ;
107+ // Cleanup on unmount or deps change
108+ return ( ) => {
109+ if ( timeoutIdRef . current ) {
110+ clearTimeout ( timeoutIdRef . current ) ;
111+ timeoutIdRef . current = null ;
112+ }
113+ } ;
114+ } , [ branches . activeBranch ?. id , branches ] ) ; // Only re-run when branch ID changes
116115
117116 // Extract restart logic into a reusable function to follow DRY principles
118117 const handleRestartSandbox = async ( ) => {
119118 const activeBranch = branches . activeBranch ;
120119 if ( ! activeBranch || restarting ) return ;
121120
122121 setRestarting ( true ) ;
123- setHasConnectionTimeout ( false ) ; // Clear timeout state on restart
124- connectionStartTimeRef . current = null ; // Reset connection tracking
122+ setHasSandboxError ( false ) ; // Clear error state on restart
125123
126124 try {
127125 const sandbox = branches . getSandboxById ( activeBranch . id ) ;
0 commit comments