Files
herdr-issue/skills/herdr-issue/scripts/ready.py
T

74 lines
3.0 KiB
Python
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""列出可執行的議題。輸入:open.json agents.json tabs.json owner/repo
阻擋關係只認 Gitea 原生 issue dependencies(tea api),不看議題內文。"""
import os, json, re, subprocess, sys
open_issues = json.load(open(sys.argv[1]))
agents = json.load(open(sys.argv[2]))
tabs = json.load(open(sys.argv[3]))
repo = sys.argv[4]
def find(o, k):
if isinstance(o, dict):
if k in o: return o[k]
for v in o.values():
r = find(v, k)
if r is not None: return r
elif isinstance(o, list):
for v in o:
r = find(v, k)
if r is not None: return r
def labels(i): return [l.strip() for l in (i.get("labels") or "").split() if l.strip()] if isinstance(i.get("labels"), str) else [l["name"] for l in i.get("labels") or []]
# Herdr 裡活著的 agent:名稱 issue-N,或掛在標籤 #N 的 tab 上
running = set()
for a in find(agents, "agents") or []:
m = re.fullmatch(r"issue-(\d+)", str(a.get("name") or ""))
if m: running.add(m.group(1))
agent_tabs = {a.get("tab_id") for a in find(agents, "agents") or []}
for t in find(tabs, "tabs") or []:
m = re.fullmatch(r"#(\d+)", str(t.get("label") or ""))
if m and t.get("tab_id") in agent_tabs: running.add(m.group(1))
def open_blockers(n):
"""擋住 #n 的 open 依賴。tea api 遇到 HTTP 錯誤仍 exit 0,所以回應不是陣列就當失敗,整個停下。"""
raw = subprocess.run(["tea", "api", "--login", os.environ["HERDR_ISSUE_LOGIN"], "--repo", repo, f"/repos/{{owner}}/{{repo}}/issues/{n}/dependencies"],
capture_output=True, text=True).stdout
try: d = json.loads(raw)
except Exception: d = None
if not isinstance(d, list):
sys.exit(f"herdr-issue: 讀取 #{n} 的依賴失敗:{raw.strip()[:300]}")
out = []
for i in d:
if i.get("state") != "open": continue
r = (i.get("repository") or {}).get("full_name", "")
out.append(("#" if r in ("", repo) else r + "#") + str(i["number"]))
return out
def spec(i):
return next((l for l in labels(i) if l.startswith("規格/#") or l.startswith("總覽/#")), "")
runnable, stale = [], []
for i in sorted(open_issues, key=lambda x: int(x["index"])):
ls = labels(i)
if "ready-for-agent" not in ls: continue
if "類型/規格" in ls or "類型/總覽" in ls: continue
n = i["index"]
if n in running: continue
if "in-progress" in ls:
stale.append(n); continue
if open_blockers(n): continue
runnable.append((n, spec(i), i["title"]))
if runnable:
print(f"可執行({len(runnable)}):編號\t規格\t標題")
for n, s, t in runnable:
print(f"#{n}\t{s}\t{t}")
else:
print("目前沒有可執行的議題。")
print()
print("Herdr 執行中:" + (" ".join(f"#{n}" for n in sorted(running, key=int)) or "無"))
if stale:
print("掛 in-progress 但沒有 agent(需處理,重跑 start 會接續):" + " ".join(f"#{n}" for n in stale))