@@ -186,6 +186,47 @@ async def _process_messages(client: ClaudeSDKClient, phase: str) -> None:
186186 _emit_tool_detail (phase , block .name , json .dumps (block .input ))
187187
188188
189+ async def kill_dev_servers (repo_dir : str ) -> None :
190+ """Kill any lingering dev server processes (node, vite, next, etc.)."""
191+ for pattern in ["node" , "vite" , "next" ]:
192+ subprocess .run (
193+ ["pkill" , "-f" , pattern ],
194+ capture_output = True ,
195+ )
196+ # Give processes time to terminate
197+ await asyncio .sleep (2 )
198+
199+
200+ async def fix_with_claude (repo_dir : str , error_message : str ) -> None :
201+ """Use Claude to diagnose and fix the dev server launch failure."""
202+ options = ClaudeAgentOptions (
203+ allowed_tools = ["Read" , "Write" , "Edit" , "Bash" , "Glob" , "Grep" ],
204+ cwd = repo_dir ,
205+ max_turns = 20 ,
206+ max_budget_usd = 1.5 ,
207+ include_partial_messages = True ,
208+ )
209+
210+ async with ClaudeSDKClient (options = options ) as client :
211+ await client .query (f"""The dev server failed to start in the project at { repo_dir } .
212+
213+ Here is the error output:
214+
215+ ```
216+ { error_message }
217+ ```
218+
219+ Please diagnose and fix the issue. Common causes include:
220+ - Missing or incorrect dependencies (run `npm install` or similar)
221+ - Build errors in the source code (syntax errors, import errors, type errors)
222+ - Port conflicts (change the port configuration)
223+ - Missing environment variables or config files
224+
225+ Fix the code so the dev server can start successfully. Make minimal, targeted changes.
226+ """ )
227+ await _process_messages (client , "implementing" )
228+
229+
189230async def launch_and_screenshot (repo_dir : str , screenshot_output : str ) -> None :
190231 """Launch dev server and take screenshot in a single session.
191232
@@ -228,6 +269,13 @@ async def launch_and_screenshot(repo_dir: str, screenshot_output: str) -> None:
228269""" )
229270 await _process_messages (client , "screenshot" )
230271
272+ # Verify screenshot was actually created
273+ if not Path (screenshot_output ).exists ():
274+ raise RuntimeError (
275+ f"Screenshot was not created at { screenshot_output } . "
276+ "The dev server likely failed to start or the screenshot command failed."
277+ )
278+
231279
232280async def main () -> None :
233281 # Read environment variables
@@ -320,8 +368,33 @@ async def main() -> None:
320368 emit_log ("implementing" , "Implementing design proposal" )
321369 await implement_changes (repo_dir , proposal_plan )
322370
323- # Launch + screenshot in a single session (shares dev server URL context)
324- await launch_and_screenshot (repo_dir , screenshot_path )
371+ # Launch + screenshot with retry loop
372+ max_retries = 2 # up to 3 total attempts
373+ last_error = None
374+ for attempt in range (max_retries + 1 ):
375+ try :
376+ await launch_and_screenshot (repo_dir , screenshot_path )
377+ last_error = None
378+ break # success
379+ except Exception as e :
380+ last_error = str (e )
381+ if attempt < max_retries :
382+ emit_log (
383+ "implementing" ,
384+ f"Dev server launch failed (attempt { attempt + 1 } /{ max_retries + 1 } ), attempting fix..." ,
385+ detail = last_error ,
386+ )
387+ await kill_dev_servers (repo_dir )
388+ await fix_with_claude (repo_dir , last_error )
389+ else :
390+ emit_log (
391+ "implementing" ,
392+ f"Dev server launch failed after { max_retries + 1 } attempts, proceeding without screenshot" ,
393+ detail = last_error ,
394+ )
395+
396+ if last_error :
397+ emit_log ("implementing" , "WARNING: Could not launch dev server, screenshot may be missing" )
325398
326399 # Step 4: Generate cumulative patch (squash everything since base_branch)
327400 emit_log ("uploading" , "Generating cumulative patch" )
0 commit comments