@@ -157,7 +157,9 @@ const subscriptions = new Map<
157157 * Called synchronously after session is created, before any prompts are sent.
158158 */
159159function subscribeToChannel ( taskRunId : string ) {
160- if ( subscriptions . has ( taskRunId ) ) return ;
160+ if ( subscriptions . has ( taskRunId ) ) {
161+ return ;
162+ }
161163
162164 const eventSubscription = trpcVanilla . agent . onSessionEvent . subscribe (
163165 { sessionId : taskRunId } ,
@@ -909,66 +911,78 @@ const useStore = create<SessionStore>()(
909911 } = task ;
910912 const isCloud = latestRun ?. environment === "cloud" ;
911913
912- // Prevent duplicate connections
913- if ( connectAttempts . has ( taskId ) ) return ;
914- if ( getSessionByTaskId ( taskId ) ?. status === "connected" ) return ;
915-
916- // Check auth first
917- const auth = getAuthCredentials ( ) ;
918- if ( ! auth ) {
919- log . error ( "Missing auth credentials" ) ;
920- const taskRunId = latestRun ?. id ?? `error-${ taskId } ` ;
921- const session = createBaseSession ( taskRunId , taskId , isCloud ) ;
922- session . status = "error" ;
923- session . errorMessage =
924- "Authentication required. Please sign in to continue." ;
925- addSession ( session ) ;
914+ // Prevent duplicate connections - CHECK AND ADD ATOMICALLY
915+ if ( connectAttempts . has ( taskId ) ) {
916+ return ;
917+ }
918+ const existingSession = getSessionByTaskId ( taskId ) ;
919+ if ( existingSession ?. status === "connected" ) {
920+ return ;
921+ }
922+ if ( existingSession ?. status === "connecting" ) {
926923 return ;
927924 }
928925
929- // For non-cloud sessions, check workspace existence (local filesystem check)
930- // This should happen before the offline check so users see workspace errors
931- if ( ! isCloud && latestRun ?. id && latestRun ?. log_url ) {
932- const workspaceResult = await trpcVanilla . workspace . verify . query ( {
933- taskId,
934- } ) ;
926+ // ADD TO SET IMMEDIATELY after checks - before any async work
927+ // This prevents the race condition where two calls both pass the check
928+ connectAttempts . add ( taskId ) ;
929+
930+ try {
931+ // Check auth first
932+ const auth = getAuthCredentials ( ) ;
933+ if ( ! auth ) {
934+ log . error ( "Missing auth credentials" ) ;
935+ const taskRunId = latestRun ?. id ?? `error-${ taskId } ` ;
936+ const session = createBaseSession ( taskRunId , taskId , isCloud ) ;
937+ session . status = "error" ;
938+ session . errorMessage =
939+ "Authentication required. Please sign in to continue." ;
940+ addSession ( session ) ;
941+ return ;
942+ }
935943
936- if ( ! workspaceResult . exists ) {
937- log . warn ( "Workspace no longer exists, showing error state" , {
944+ // For non-cloud sessions, check workspace existence (local filesystem check)
945+ // This should happen before the offline check so users see workspace errors
946+ if ( ! isCloud && latestRun ?. id && latestRun ?. log_url ) {
947+ const workspaceResult = await trpcVanilla . workspace . verify . query ( {
938948 taskId,
939- missingPath : workspaceResult . missingPath ,
940949 } ) ;
941- const { rawEntries } = await fetchSessionLogs ( latestRun . log_url ) ;
942- const events = convertStoredEntriesToEvents ( rawEntries ) ;
943950
944- const session = createBaseSession ( latestRun . id , taskId , false ) ;
945- session . events = events ;
946- session . logUrl = latestRun . log_url ;
947- session . status = "error" ;
948- session . errorMessage = workspaceResult . missingPath
949- ? `Working directory no longer exists: ${ workspaceResult . missingPath } `
950- : "The working directory for this task no longer exists. Please start a new task." ;
951+ if ( ! workspaceResult . exists ) {
952+ log . warn ( "Workspace no longer exists, showing error state" , {
953+ taskId,
954+ missingPath : workspaceResult . missingPath ,
955+ } ) ;
956+ const { rawEntries } = await fetchSessionLogs (
957+ latestRun . log_url ,
958+ ) ;
959+ const events = convertStoredEntriesToEvents ( rawEntries ) ;
960+
961+ const session = createBaseSession ( latestRun . id , taskId , false ) ;
962+ session . events = events ;
963+ session . logUrl = latestRun . log_url ;
964+ session . status = "error" ;
965+ session . errorMessage = workspaceResult . missingPath
966+ ? `Working directory no longer exists: ${ workspaceResult . missingPath } `
967+ : "The working directory for this task no longer exists. Please start a new task." ;
968+
969+ addSession ( session ) ;
970+ return ;
971+ }
972+ }
951973
974+ // Don't try to connect if offline (agent connection requires internet)
975+ if ( ! getIsOnline ( ) ) {
976+ log . info ( "Skipping connection attempt - offline" , { taskId } ) ;
977+ const taskRunId = latestRun ?. id ?? `offline-${ taskId } ` ;
978+ const session = createBaseSession ( taskRunId , taskId , isCloud ) ;
979+ session . status = "disconnected" ;
980+ session . errorMessage =
981+ "No internet connection. Connect when you're back online." ;
952982 addSession ( session ) ;
953983 return ;
954984 }
955- }
956-
957- // Don't try to connect if offline (agent connection requires internet)
958- if ( ! getIsOnline ( ) ) {
959- log . info ( "Skipping connection attempt - offline" , { taskId } ) ;
960- const taskRunId = latestRun ?. id ?? `offline-${ taskId } ` ;
961- const session = createBaseSession ( taskRunId , taskId , isCloud ) ;
962- session . status = "disconnected" ;
963- session . errorMessage =
964- "No internet connection. Connect when you're back online." ;
965- addSession ( session ) ;
966- return ;
967- }
968-
969- connectAttempts . add ( taskId ) ;
970985
971- try {
972986 if ( isCloud && latestRun ?. id && latestRun ?. log_url ) {
973987 await connectToCloudSession (
974988 taskId ,
@@ -1025,7 +1039,9 @@ const useStore = create<SessionStore>()(
10251039
10261040 disconnectFromTask : async ( taskId ) => {
10271041 const session = getSessionByTaskId ( taskId ) ;
1028- if ( ! session ) return ;
1042+ if ( ! session ) {
1043+ return ;
1044+ }
10291045
10301046 if ( session . isCloud ) {
10311047 stopCloudPolling ( session . taskRunId ) ;
@@ -1035,7 +1051,10 @@ const useStore = create<SessionStore>()(
10351051 sessionId : session . taskRunId ,
10361052 } ) ;
10371053 } catch ( error ) {
1038- log . error ( "Failed to cancel session" , error ) ;
1054+ log . error ( "Failed to cancel agent session" , {
1055+ taskRunId : session . taskRunId ,
1056+ error,
1057+ } ) ;
10391058 }
10401059 unsubscribeFromChannel ( session . taskRunId ) ;
10411060 }
0 commit comments