From 0ad56e1f0a17dc0540e4838984ca95fd8d57072b Mon Sep 17 00:00:00 2001 From: Dev Agent Date: Fri, 22 May 2026 13:52:46 +0300 Subject: [PATCH] fix: tini entrypoint, event routing wildcard, orphan recovery --- Dockerfile | 3 +++ src/main.py | 11 +++++++++++ src/qg/checks.py | 3 +++ src/webhooks/gitea.py | 2 +- src/webhooks/plane.py | 11 +++++++++++ 5 files changed, 29 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 3544f75..33c0eec 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,6 +13,9 @@ RUN apt-get update && \ WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt +RUN apt-get update && apt-get install -y --no-install-recommends tini && rm -rf /var/lib/apt/lists/* && \ + git config --global --add safe.directory '*' COPY src/ src/ RUN mkdir -p /app/data/runs +ENTRYPOINT ["tini", "--"] CMD ["uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "8500"] diff --git a/src/main.py b/src/main.py index 92c6c34..7d84883 100644 --- a/src/main.py +++ b/src/main.py @@ -15,6 +15,17 @@ logging.basicConfig( @asynccontextmanager async def lifespan(app: FastAPI): init_db() + # Recover orphaned runs + from .db import get_db + conn = get_db() + orphans = conn.execute( + "UPDATE agent_runs SET finished_at=datetime('now'), exit_code=-1 " + "WHERE finished_at IS NULL AND started_at < datetime('now', '-35 minutes')" + ).rowcount + conn.commit() + conn.close() + if orphans: + logging.getLogger('orchestrator').warning(f'Recovered {orphans} orphaned agent runs') yield diff --git a/src/qg/checks.py b/src/qg/checks.py index cfd3c42..b2e74e6 100644 --- a/src/qg/checks.py +++ b/src/qg/checks.py @@ -100,6 +100,9 @@ def check_review_approved(repo: str, pr_number: int) -> tuple[bool, str]: approved = 0 changes_requested = 0 for review in reviews: + # Skip stale reviews (dismissed by new commits) + if review.get("stale", False): + continue state = review.get("state", "").upper() if state == "APPROVED": approved += 1 diff --git a/src/webhooks/gitea.py b/src/webhooks/gitea.py index d9417b8..141e4da 100644 --- a/src/webhooks/gitea.py +++ b/src/webhooks/gitea.py @@ -62,7 +62,7 @@ async def gitea_webhook(request: Request): if event_type == "push": await handle_push(payload) - elif event_type in ("pull_request", "pull_request_approved", "pull_request_review_approved"): + elif event_type.startswith("pull_request"): await handle_pr(payload) elif event_type == "status": await handle_ci_status(payload) diff --git a/src/webhooks/plane.py b/src/webhooks/plane.py index 395298c..a75be11 100644 --- a/src/webhooks/plane.py +++ b/src/webhooks/plane.py @@ -122,6 +122,17 @@ async def handle_work_item_created(data: dict): logger.info(f"Task created: {work_item_id} ({name}), branch={branch}, stage=analysis") + # Launch analyst agent + try: + task_row = get_db().execute("SELECT id FROM tasks WHERE work_item_id=?", (work_item_id,)).fetchone() + if task_row: + task_id = task_row[0] + task_desc = f"Work item: {work_item_id}\nRepo: {repo}\nBranch: {branch}\nStage: analysis\nTitle: {name}" + run_id = launcher.launch("analyst", repo, task_desc, task_id=task_id) + logger.info(f"Task {task_id}: launched analyst (run_id={run_id})") + except Exception as e: + logger.error(f"Failed to launch analyst for {work_item_id}: {e}") + async def handle_comment(data: dict): """