From a1b98a30cafb70ff5cb22d7258746297ea9fd3e8 Mon Sep 17 00:00:00 2001 From: cfdaily Date: Mon, 18 May 2026 11:39:02 +0800 Subject: [PATCH] auto-sync: 2026-05-18 11:39:02 --- src/daemon/ticker.py | 90 +++++++++++++++++++++++++++----------------- 1 file changed, 56 insertions(+), 34 deletions(-) diff --git a/src/daemon/ticker.py b/src/daemon/ticker.py index e6eeb33..bc17d23 100644 --- a/src/daemon/ticker.py +++ b/src/daemon/ticker.py @@ -192,7 +192,7 @@ class Ticker: "dispatched": [], "review_dispatched": [], "zombie_reclaimed": [], - "cards_processed": [], + "parents_refreshed": [], } # 保存当前 project_id(供 _dispatch_pending 使用) @@ -210,61 +210,83 @@ class Ticker: zombie_reclaimed = self._check_timeouts(db_path) result["zombie_reclaimed"] = zombie_reclaimed - # 4. per-Card 调度(v2.7:只处理 active cards) - card_ops = CardOps(db_path) - active_cards = card_ops.list_cards(status="active") + # 4. 调度 pending 任务 + if self.dispatcher and self.spawner: + dispatched = await self._dispatch_pending(db_path, project_id) + result["dispatched"] = dispatched - for card in active_cards: - card_result = await self._tick_card(db_path, project_id, card.id) - result["dispatched"].extend(card_result.get("dispatched", [])) - result["review_dispatched"].extend(card_result.get("review_dispatched", [])) - result["cards_processed"].append(card.id) + # 5. 调度审查任务 + if self.dispatcher and self.spawner: + review_dispatched = await self._dispatch_reviews(db_path, project_id) + result["review_dispatched"] = review_dispatched - # 5. 写 daemon_tick 事件(直接用 get_connection,不再 Blackboard() → init_db) + # 6. 聚合父 Task 状态(v2.7) + parents_refreshed = self._refresh_parent_statuses(db_path) + result["parents_refreshed"] = parents_refreshed + + # 7. 写 daemon_tick 事件 conn = get_connection(db_path) try: conn.execute("BEGIN IMMEDIATE") conn.execute( - "INSERT INTO events (task_id, agent, event_type, detail, card_id) VALUES (?,?,?,?,?)", + "INSERT INTO events (task_id, agent, event_type, detail) VALUES (?,?,?,?)", (None, "daemon", "daemon_tick", json.dumps({"tick": self._tick_count, "advanced_count": len(advanced), - "cards_processed": len(active_cards)}), - None), + "parents_refreshed": len(parents_refreshed)})), ) conn.commit() finally: conn.close() - # 6. 扫描后状态 + # 8. 扫描后状态 result["summary_after"] = queries.task_summary() return result - async def _tick_card(self, db_path: Path, project_id: str, - card_id: str) -> Dict[str, Any]: - """单 Card 的 tick 处理""" - result: Dict[str, Any] = { - "dispatched": [], - "review_dispatched": [], - } + # ------------------------------------------------------------------ + # 父 Task 状态聚合 + # ------------------------------------------------------------------ + def _refresh_parent_statuses(self, db_path: Path) -> List[str]: + """全量扫描有子 Task 的父 Task,刷新聚合状态 + + 跳过手动状态(cancelled)的父 Task。 + """ queries = Queries(db_path) + refreshed: List[str] = [] - # 调度 pending 任务 - if self.dispatcher and self.spawner: - dispatched = await self._dispatch_pending(db_path, project_id, card_id) - result["dispatched"] = dispatched + # 找出所有有子 Task 的父 Task ID + conn = get_connection(db_path) + try: + parent_rows = conn.execute( + "SELECT DISTINCT parent_task FROM tasks WHERE parent_task IS NOT NULL" + ).fetchall() + parent_ids = [r["parent_task"] for r in parent_rows] + finally: + conn.close() - # 调度审查任务 - if self.dispatcher and self.spawner: - review_dispatched = await self._dispatch_reviews(db_path, project_id, card_id) - result["review_dispatched"] = review_dispatched + for pid in parent_ids: + computed = queries.compute_parent_status(pid) + if computed is None: + continue + # 直接更新(跳过手动状态已在 compute 里判断) + conn = get_connection(db_path) + try: + parent = conn.execute( + "SELECT status FROM tasks WHERE id=?", (pid,) + ).fetchone() + if parent and parent["status"] != computed: + conn.execute( + "UPDATE tasks SET status=?, updated_at=datetime('now') WHERE id=?", + (computed, pid), + ) + conn.commit() + refreshed.append(pid) + logger.info("Parent %s status aggregated: → %s", pid, computed) + finally: + conn.close() - # 刷新 Card 状态 - card_ops = CardOps(db_path) - card_ops.refresh_card_status(card_id) - - return result + return refreshed # ------------------------------------------------------------------ # 依赖推进