@@ -12,6 +12,7 @@ import { useAuthStore } from '../auth/store'
1212import {
1313 buildStreamUrl ,
1414 createContainerSession ,
15+ getContainerSession ,
1516 sendMessage ,
1617 stopContainerSession ,
1718} from './containerApi'
@@ -68,21 +69,24 @@ export default function ContainerSession({
6869 // Create session on mount
6970 useEffect ( ( ) => {
7071 mountedRef . current = true
71- let cancelled = false
72+ const abortController = new AbortController ( )
7273
7374 async function init ( ) {
7475 try {
7576 setStatus ( 'starting' )
7677 appendLine ( `Starting ${ skillName } for ${ repoFullName } #${ prNumber } ...` )
7778
78- const created = await createContainerSession ( {
79- installation_id : installationId ,
80- pr_number : prNumber ,
81- repo_full_name : repoFullName ,
82- skill_name : skillName ,
83- } )
79+ const created = await createContainerSession (
80+ {
81+ installation_id : installationId ,
82+ pr_number : prNumber ,
83+ repo_full_name : repoFullName ,
84+ skill_name : skillName ,
85+ } ,
86+ abortController . signal ,
87+ )
8488
85- if ( cancelled ) return
89+ if ( abortController . signal . aborted ) return
8690
8791 setSession ( created )
8892 setStatus ( created . status )
@@ -94,14 +98,36 @@ export default function ContainerSession({
9498 appendLine ( '[error] Container failed to start.' )
9599 }
96100 } catch ( err ) {
97- if ( cancelled ) return
101+ if ( abortController . signal . aborted ) return
98102 const msg = err instanceof Error ? err . message : 'Unknown error'
99103 setError ( msg )
100104 setStatus ( 'failed' )
101105 appendLine ( `[error] ${ msg } ` )
102106 }
103107 }
104108
109+ async function pollSessionStatus ( sessionId : string ) {
110+ try {
111+ const fresh = await getContainerSession ( sessionId )
112+ if ( ! mountedRef . current ) return
113+ setStatus ( fresh . status )
114+ if ( fresh . status === 'completed' ) {
115+ appendLine ( 'Session completed.' )
116+ } else if ( fresh . status === 'failed' ) {
117+ setError ( 'Container failed' )
118+ appendLine ( '[error] Container failed.' )
119+ } else if ( fresh . status === 'running' ) {
120+ appendLine ( '[reconnecting] Stream dropped, container still running...' )
121+ connectStream ( sessionId )
122+ }
123+ } catch {
124+ if ( ! mountedRef . current ) return
125+ setStatus ( 'failed' )
126+ setError ( 'Lost connection to session' )
127+ appendLine ( '[error] Lost connection to session.' )
128+ }
129+ }
130+
105131 function connectStream ( sessionId : string ) {
106132 const accessToken = useAuthStore . getState ( ) . accessToken
107133 if ( ! accessToken ) {
@@ -176,19 +202,19 @@ export default function ContainerSession({
176202 return
177203 }
178204
179- // Native error — connection dropped
205+ // Native error — connection dropped. Poll backend for actual status
206+ // instead of immediately marking as failed.
180207 if ( source . readyState === EventSource . CLOSED ) {
181208 eventSourceRef . current = null
182- // Only mark as failed if we haven't already completed
183- setStatus ( ( prev ) => ( prev === 'completed' ? prev : 'failed' ) )
209+ pollSessionStatus ( sessionId )
184210 }
185211 } )
186212 }
187213
188214 init ( )
189215
190216 return ( ) => {
191- cancelled = true
217+ abortController . abort ( )
192218 mountedRef . current = false
193219 if ( eventSourceRef . current ) {
194220 eventSourceRef . current . close ( )
0 commit comments