Spawn a coding agent subprocess for a specific feature.
(self, feature_id: int)
| 815 | return True, f"Started batch [{', '.join(str(fid) for fid in feature_ids)}]" |
| 816 | |
| 817 | def _spawn_coding_agent(self, feature_id: int) -> tuple[bool, str]: |
| 818 | """Spawn a coding agent subprocess for a specific feature.""" |
| 819 | # Create abort event |
| 820 | abort_event = threading.Event() |
| 821 | |
| 822 | # Start subprocess for this feature |
| 823 | cmd = [ |
| 824 | sys.executable, |
| 825 | "-u", # Force unbuffered stdout/stderr |
| 826 | str(AUTOFORGE_ROOT / "autonomous_agent_demo.py"), |
| 827 | "--project-dir", str(self.project_dir), |
| 828 | "--max-iterations", "1", |
| 829 | "--agent-type", "coding", |
| 830 | "--feature-id", str(feature_id), |
| 831 | ] |
| 832 | if self.model: |
| 833 | cmd.extend(["--model", self.model]) |
| 834 | if self.yolo_mode: |
| 835 | cmd.append("--yolo") |
| 836 | |
| 837 | try: |
| 838 | # CREATE_NO_WINDOW on Windows prevents console window pop-ups |
| 839 | # stdin=DEVNULL prevents blocking on stdin reads |
| 840 | # encoding="utf-8" and errors="replace" fix Windows CP1252 issues |
| 841 | popen_kwargs: dict[str, Any] = { |
| 842 | "stdin": subprocess.DEVNULL, |
| 843 | "stdout": subprocess.PIPE, |
| 844 | "stderr": subprocess.STDOUT, |
| 845 | "text": True, |
| 846 | "encoding": "utf-8", |
| 847 | "errors": "replace", |
| 848 | "cwd": str(self.project_dir), # Run from project dir so CLI creates .claude/ in project |
| 849 | "env": {**os.environ, "PYTHONUNBUFFERED": "1"}, |
| 850 | } |
| 851 | if sys.platform == "win32": |
| 852 | popen_kwargs["creationflags"] = subprocess.CREATE_NO_WINDOW |
| 853 | |
| 854 | proc = subprocess.Popen(cmd, **popen_kwargs) |
| 855 | except Exception as e: |
| 856 | # Reset in_progress on failure |
| 857 | session = self.get_session() |
| 858 | try: |
| 859 | feature = session.query(Feature).filter(Feature.id == feature_id).first() |
| 860 | if feature: |
| 861 | feature.in_progress = False |
| 862 | session.commit() |
| 863 | finally: |
| 864 | session.close() |
| 865 | return False, f"Failed to start agent: {e}" |
| 866 | |
| 867 | with self._lock: |
| 868 | self.running_coding_agents[feature_id] = proc |
| 869 | self.abort_events[feature_id] = abort_event |
| 870 | |
| 871 | # Start output reader thread |
| 872 | threading.Thread( |
| 873 | target=self._read_output, |
| 874 | args=(feature_id, proc, abort_event, "coding"), |
no test coverage detected