#!/usr/bin/env python3 """ Dev Agent - Find next task with three-phase discovery. Phase 1a: Continue unfinished main tasks (开发中/修复中 with pending subtasks) Phase 1a.5: Pipeline recovery: (A) Stuck subtasks: main=待测 but has unfinished subtasks (B) Stale review-fail bugs: main=待测, completed/待测 subtask has 待修复 bugs Phase 1b: New tasks (待办 requirement / 待修复 bug) Outputs JSON to stdout, or "NO_TASKS" if nothing found. """ import json, os, sys sys.path.insert(0, os.path.expanduser( "~/.hermes/skills/productivity/feishu-todo-sync/references")) from pipeline_api import load_config, fetch_all AH, AT, RT, BT = load_config() def get_subtasks(records, parent_id): subs = [] for r in records: parent = r.get("fields", {}).get("父记录") if parent and isinstance(parent, list) and len(parent) > 0: entry = parent[0] if entry is None: # defend against [None] continue pids = entry.get("record_ids") if pids and parent_id in pids: subs.append(r) return subs def is_main_task(record): parent = record.get("fields", {}).get("父记录") if not parent or not isinstance(parent, list) or len(parent) == 0: return True entry = parent[0] if entry is None: # defend against [None] return True pids = entry.get("record_ids") return pids is None def sort_by_priority(items): pri_map = {"P0-紧急": 0, "P1-高": 1, "P2-中": 2, "P3-低": 3, "P3": 3} return sorted(items, key=lambda x: pri_map.get( x.get("fields", {}).get("优先级", "P3-低"), 3)) req_records = fetch_all(RT) bug_records = fetch_all(BT) result = None # ============================================================ # PHASE 1a: Continue unfinished main tasks # ============================================================ for r in sort_by_priority(req_records): if not is_main_task(r): continue status = r.get("fields", {}).get("状态", "") if status != "开发中": continue subs = get_subtasks(req_records, r["record_id"]) pending_subs = [s for s in subs if s.get("fields", {}).get("状态", "") in ("待办", "开发中", "自测中")] if pending_subs: result = { "phase": "1a-continue", "table": "r", "record_id": r["record_id"], "title": r.get("fields", {}).get("需求标题", ""), "status": status, "all_subtasks": [{"id": s["record_id"], "title": s.get("fields", {}).get("需求标题", ""), "status": s.get("fields", {}).get("状态", "")} for s in subs], "pending_subtasks": [{"id": s["record_id"], "title": s.get("fields", {}).get("需求标题", ""), "status": s.get("fields", {}).get("状态", "")} for s in pending_subs], } break if not result: for r in sort_by_priority(bug_records): if not is_main_task(r): continue status = r.get("fields", {}).get("状态", "") if status != "修复中": continue subs = get_subtasks(bug_records, r["record_id"]) pending_subs = [s for s in subs if s.get("fields", {}).get("状态", "") in ("待修复", "修复中", "自测中")] if pending_subs: result = { "phase": "1a-continue", "table": "b", "record_id": r["record_id"], "title": r.get("fields", {}).get("Bug标题", ""), "status": status, "all_subtasks": [{"id": s["record_id"], "title": s.get("fields", {}).get("Bug标题", ""), "status": s.get("fields", {}).get("状态", "")} for s in subs], "pending_subtasks": [{"id": s["record_id"], "title": s.get("fields", {}).get("Bug标题", ""), "status": s.get("fields", {}).get("状态", "")} for s in pending_subs], } break # ============================================================ # PHASE 1a.5: Pipeline recovery # ============================================================ if not result: # (A) Stuck subtasks: main=待测, but has unfinished subtasks for r in sort_by_priority(req_records): if not is_main_task(r): continue status = r.get("fields", {}).get("状态", "") if status != "待测": continue subs = get_subtasks(req_records, r["record_id"]) unfinished = [s for s in subs if s.get("fields", {}).get("状态", "") in ("待办", "开发中", "自测中")] if unfinished: result = { "phase": "1a.5A-stuck", "table": "r", "record_id": r["record_id"], "title": r.get("fields", {}).get("需求标题", ""), "status": status, "unfinished_subtasks": [ {"id": s["record_id"], "title": s.get("fields", {}).get("需求标题", ""), "status": s.get("fields", {}).get("状态", "")} for s in unfinished], } break if not result: for r in sort_by_priority(bug_records): if not is_main_task(r): continue status = r.get("fields", {}).get("状态", "") if status != "待测": continue subs = get_subtasks(bug_records, r["record_id"]) unfinished = [s for s in subs if s.get("fields", {}).get("状态", "") in ("待修复", "修复中", "自测中")] if unfinished: result = { "phase": "1a.5A-stuck", "table": "b", "record_id": r["record_id"], "title": r.get("fields", {}).get("Bug标题", ""), "status": status, "unfinished_subtasks": [ {"id": s["record_id"], "title": s.get("fields", {}).get("Bug标题", ""), "status": s.get("fields", {}).get("状态", "")} for s in unfinished], } break # (B) Stale review-fail bugs if not result: for r in sort_by_priority(req_records): if not is_main_task(r): continue status = r.get("fields", {}).get("状态", "") if status != "待测": continue subs = get_subtasks(req_records, r["record_id"]) for s in subs: s_status = s.get("fields", {}).get("状态", "") if s_status not in ("已完成", "待测"): continue child_bugs = get_subtasks(bug_records, s["record_id"]) pending_bugs = [b for b in child_bugs if b.get("fields", {}).get("状态", "") in ("待修复", "修复中", "自测中")] if pending_bugs: result = { "phase": "1a.5B-stale-bug", "table": "r", "record_id": r["record_id"], "title": r.get("fields", {}).get("需求标题", ""), "status": status, "stale_subtask": { "id": s["record_id"], "title": s.get("fields", {}).get("需求标题", ""), "status": s_status}, "pending_bugs": [ {"id": b["record_id"], "title": b.get("fields", {}).get("Bug标题", ""), "status": b.get("fields", {}).get("状态", "")} for b in pending_bugs], } break if result: break # ============================================================ # PHASE 1b: New tasks # ============================================================ if not result: for r in sort_by_priority(req_records): if not is_main_task(r): continue status = r.get("fields", {}).get("状态", "") if status != "待办": continue subs = get_subtasks(req_records, r["record_id"]) result = { "phase": "1b-new", "table": "r", "record_id": r["record_id"], "title": r.get("fields", {}).get("需求标题", ""), "priority": r.get("fields", {}).get("优先级", ""), "status": status, "subtasks": [{"id": s["record_id"], "title": s.get("fields", {}).get("需求标题", ""), "status": s.get("fields", {}).get("状态", "")} for s in subs], } break if not result: for r in sort_by_priority(bug_records): if not is_main_task(r): continue status = r.get("fields", {}).get("状态", "") if status != "待修复": continue subs = get_subtasks(bug_records, r["record_id"]) result = { "phase": "1b-new", "table": "b", "record_id": r["record_id"], "title": r.get("fields", {}).get("Bug标题", ""), "priority": r.get("fields", {}).get("优先级", ""), "status": status, "subtasks": [{"id": s["record_id"], "title": s.get("fields", {}).get("Bug标题", ""), "status": s.get("fields", {}).get("状态", "")} for s in subs], } break if result: print(json.dumps(result, ensure_ascii=False, indent=2)) else: print("NO_TASKS")