99import os
1010import subprocess
1111import tempfile
12+ import time
1213from dataclasses import dataclass , field
1314from pathlib import Path
1415
@@ -30,6 +31,9 @@ class AuthCheckResult:
3031 success : bool
3132 auth_methods : list [AuthMethod ] = field (default_factory = list )
3233 error : str | None = None
34+ stderr_tail : str | None = None
35+ duration_seconds : float | None = None
36+ process_exit_code : int | None = None
3337
3438
3539def parse_auth_methods (auth_methods_raw : list [dict ]) -> list [AuthMethod ]:
@@ -122,6 +126,29 @@ def read_jsonrpc(proc: subprocess.Popen, timeout: float) -> dict | None:
122126 ) from e
123127
124128
129+ def _collect_proc_diagnostics (proc : subprocess .Popen ) -> tuple [str | None , int | None ]:
130+ """Collect stderr tail and exit code from a process (non-blocking).
131+
132+ Returns:
133+ (stderr_tail, exit_code) — either may be None if unavailable.
134+ """
135+ import select
136+
137+ exit_code = proc .poll ()
138+
139+ stderr_tail : str | None = None
140+ try :
141+ ready , _ , _ = select .select ([proc .stderr ], [], [], 0.5 )
142+ if ready :
143+ data = proc .stderr .read (8192 )
144+ if data :
145+ stderr_tail = data [- 4000 :]
146+ except Exception :
147+ pass
148+
149+ return stderr_tail , exit_code
150+
151+
125152def run_auth_check (
126153 cmd : list [str ],
127154 cwd : Path ,
@@ -151,6 +178,7 @@ def run_auth_check(
151178 full_env ["HOME" ] = sandbox_home
152179
153180 proc = None
181+ t0 = time .monotonic ()
154182 try :
155183 # Make binary executable if needed
156184 exe_path = Path (cmd [0 ])
@@ -194,15 +222,25 @@ def run_auth_check(
194222 response = read_jsonrpc (proc , timeout )
195223
196224 if response is None :
225+ duration = time .monotonic () - t0
226+ stderr_tail , exit_code = _collect_proc_diagnostics (proc )
197227 return AuthCheckResult (
198228 success = False ,
199229 error = f"Timeout after { timeout } s waiting for initialize response" ,
230+ stderr_tail = stderr_tail ,
231+ duration_seconds = duration ,
232+ process_exit_code = exit_code ,
200233 )
201234
202235 if "error" in response :
236+ duration = time .monotonic () - t0
237+ stderr_tail , exit_code = _collect_proc_diagnostics (proc )
203238 return AuthCheckResult (
204239 success = False ,
205240 error = f"Agent error: { response ['error' ]} " ,
241+ stderr_tail = stderr_tail ,
242+ duration_seconds = duration ,
243+ process_exit_code = exit_code ,
206244 )
207245
208246 result = response .get ("result" , {})
@@ -214,16 +252,32 @@ def run_auth_check(
214252 # Validate
215253 is_valid , message = validate_auth_methods (auth_methods )
216254
255+ if is_valid :
256+ return AuthCheckResult (
257+ success = True ,
258+ auth_methods = auth_methods ,
259+ )
260+
261+ duration = time .monotonic () - t0
262+ stderr_tail , exit_code = _collect_proc_diagnostics (proc )
217263 return AuthCheckResult (
218- success = is_valid ,
264+ success = False ,
219265 auth_methods = auth_methods ,
220- error = None if is_valid else message ,
266+ error = message ,
267+ stderr_tail = stderr_tail ,
268+ duration_seconds = duration ,
269+ process_exit_code = exit_code ,
221270 )
222271
223272 except Exception as e :
273+ duration = time .monotonic () - t0
274+ stderr_tail , exit_code = _collect_proc_diagnostics (proc ) if proc else (None , None )
224275 return AuthCheckResult (
225276 success = False ,
226277 error = f"Error during auth check: { type (e ).__name__ } : { e } " ,
278+ stderr_tail = stderr_tail ,
279+ duration_seconds = duration ,
280+ process_exit_code = exit_code ,
227281 )
228282 finally :
229283 if proc :
0 commit comments