@@ -43,6 +43,7 @@ const PERMISSION_PROMPT_TIMEOUT: Duration = Duration::from_secs(8);
4343const TTY_PERMISSION_TRANSCRIPT_GRACE : Duration = Duration :: from_millis ( 1_500 ) ;
4444const TTY_QUESTION_FORM_SETTLE : Duration = Duration :: from_millis ( 250 ) ;
4545const MCP_PROXY_RESPONSE_TIMEOUT : Duration = Duration :: from_secs ( 30 ) ;
46+ const MCP_PROXY_REQUEST_LINE_TIMEOUT : Duration = Duration :: from_millis ( 250 ) ;
4647const PTY_TERMINATE_TIMEOUT : Duration = Duration :: from_secs ( 5 ) ;
4748const TTY_SESSION_LOCK_RETRY_TIMEOUT : Duration = Duration :: from_secs ( 8 ) ;
4849const TTY_SESSION_LOCK_RETRY_DELAY : Duration = Duration :: from_millis ( 300 ) ;
@@ -901,10 +902,23 @@ async fn service_pending_mcp_proxy_requests_for_runtime(
901902 Err ( error) if error. kind ( ) == std:: io:: ErrorKind :: WouldBlock => return Ok ( ( ) ) ,
902903 Err ( error) => return Err ( error. into ( ) ) ,
903904 } ;
905+ stream. set_read_timeout ( Some ( MCP_PROXY_REQUEST_LINE_TIMEOUT ) ) ?;
904906 let mut line = String :: new ( ) ;
905907 {
906908 let mut reader = StdBufReader :: new ( stream. try_clone ( ) ?) ;
907- reader. read_line ( & mut line) ?;
909+ match reader. read_line ( & mut line) {
910+ Ok ( _) => { }
911+ Err ( error)
912+ if matches ! (
913+ error. kind( ) ,
914+ std:: io:: ErrorKind :: WouldBlock | std:: io:: ErrorKind :: TimedOut
915+ ) =>
916+ {
917+ logging:: event ( "mcp_proxy_skip reason=request_line_timeout" ) ;
918+ continue ;
919+ }
920+ Err ( error) => return Err ( error. into ( ) ) ,
921+ }
908922 }
909923 if line. trim ( ) . is_empty ( ) {
910924 continue ;
@@ -1037,12 +1051,17 @@ async fn submit_prompt_and_tail_stream(
10371051}
10381052
10391053async fn submit_prompt_to_tty ( process : & mut PtyProcess , prompt : & str ) -> Result < ( ) > {
1054+ logging:: event ( format ! (
1055+ "prompt_submit start content_chars={}" ,
1056+ prompt. chars( ) . count( )
1057+ ) ) ;
10401058 process. write_all ( & bracketed_paste_input ( prompt) ) ?;
10411059 tokio:: time:: sleep ( Duration :: from_millis ( 120 ) ) . await ;
10421060 if tty_output_still_editing_prompt ( & process. recent_output ( ) , prompt) {
10431061 logging:: event ( "prompt_submit_retry reason=prompt_still_visible" ) ;
10441062 process. write_all ( b"\r " ) ?;
10451063 }
1064+ logging:: event ( "prompt_submit done" ) ;
10461065 Ok ( ( ) )
10471066}
10481067
@@ -3517,6 +3536,10 @@ async fn prepare_tty_for_prompt(process: &mut PtyProcess) -> Result<()> {
35173536 }
35183537 if tty_output_accepts_prompt ( & output) {
35193538 tokio:: time:: sleep ( TTY_READY_SETTLE ) . await ;
3539+ logging:: event ( format ! (
3540+ "tty_ready stage=prepare elapsed_ms={}" ,
3541+ started. elapsed( ) . as_millis( )
3542+ ) ) ;
35203543 return Ok ( ( ) ) ;
35213544 }
35223545 if started. elapsed ( ) > TTY_STARTUP_TIMEOUT {
@@ -3576,7 +3599,10 @@ async fn prepare_tty_for_prompt_with_mcp(
35763599 }
35773600 if tty_output_accepts_prompt ( & output) {
35783601 tokio:: time:: sleep ( TTY_READY_SETTLE ) . await ;
3579- service_pending_mcp_proxy_requests_for_runtime ( input, runtime, sdk_state) . await ?;
3602+ logging:: event ( format ! (
3603+ "tty_ready stage=prepare_mcp elapsed_ms={}" ,
3604+ started. elapsed( ) . as_millis( )
3605+ ) ) ;
35803606 return Ok ( ( ) ) ;
35813607 }
35823608 if started. elapsed ( ) > TTY_STARTUP_TIMEOUT {
@@ -4300,6 +4326,24 @@ mod tests {
43004326 assert ! ( tty_output_accepts_prompt( output) ) ;
43014327 }
43024328
4329+ #[ cfg( unix) ]
4330+ #[ tokio:: test]
4331+ async fn sdk_mcp_proxy_connection_without_line_does_not_block_prepare_loop ( ) {
4332+ use std:: os:: unix:: net:: UnixStream ;
4333+
4334+ let runtime = create_sdk_mcp_runtime ( vec ! [ "conductor" . to_owned( ) ] ) . unwrap ( ) ;
4335+ let _held_open = UnixStream :: connect ( & runtime. socket_path ) . unwrap ( ) ;
4336+ let ( _tx, mut rx) = mpsc:: channel ( 1 ) ;
4337+ let mut sdk_state = SdkStreamState :: new ( & [ ] ) ;
4338+ let started = Instant :: now ( ) ;
4339+
4340+ service_pending_mcp_proxy_requests_for_runtime ( & mut rx, & runtime, & mut sdk_state)
4341+ . await
4342+ . unwrap ( ) ;
4343+
4344+ assert ! ( started. elapsed( ) < Duration :: from_secs( 1 ) ) ;
4345+ }
4346+
43034347 #[ test]
43044348 fn keeps_english_question_leader_in_tty_question_prompt ( ) {
43054349 let output = "\
0 commit comments