← back to Chief Of Operations

scripts/steve_todo.py

46 lines

#!/usr/bin/env python3
"""One to-do list for Steve: every BLOCKED ticket, grouped by what it waits on (TK-12235). Read-only."""
import json, re, time
from pathlib import Path
HOME=Path.home(); EV=HOME/'.claude/tickets/events.jsonl'; PA=HOME/'.claude/yolo-queue/pending-approval'
T={}
for l in open(EV, errors='replace'):
    try: e=json.loads(l)
    except Exception: continue
    i=e.get('id'); ty=e.get('type')
    if not i or ty=='read': continue
    t=T.setdefault(i,{'id':i,'title':'','project':'','status':'open','last':'','last_ts':''})
    if ty=='create': t['title']=e.get('title',''); t['project']=e.get('project','')
    if ty=='status': t['status']=e.get('status')
    txt=e.get('text') or e.get('body') or ''
    if txt and ty in ('comment','action','note','create','status'): t['last']=txt; t['last_ts']=e.get('ts','')
    elif e.get('ts'): t['last_ts']=e.get('ts')
memos=[p.name for p in PA.glob('*.md')] if PA.exists() else []
def memo_for(i):
    n=i.split('-')[0]+'-'+i.split('-')[1]
    return [m for m in memos if n in m][:2]
def kind(t,m):
    s=(t['title']+' '+t['last']).lower()
    if re.search(r'password|credential|api key|token|oauth|login|sign.?in|2fa|re-?consent|secret',s): return '1 Password / login / key'
    if re.search(r'!\s*(ssh|sudo|bash|launchctl)|paste|run this|console|click|in-app|app store connect|asc ',s): return '2 Paste or console click'
    if m or re.search(r'pending-approval|approve|gated|memo',s): return '3 Approve a memo'
    if re.search(r'decid|which|choose|question|clarif|confirm|ruling|\?',s): return '4 Decision from you'
    return '5 Unclear - needs triage'
B=[t for t in T.values() if t['status']=='blocked']
groups={}
for t in B:
    m=memo_for(t['id']); groups.setdefault(kind(t,m),[]).append((t,m))
out=[f"# Steve's to-do list — {len(B)} blocked tickets ({time.strftime('%Y-%m-%d %H:%M')})",'']
for g in sorted(groups):
    rows=sorted(groups[g],key=lambda x:x[0]['last_ts'],reverse=True)
    out.append(f"## {g[2:]} ({len(rows)})")
    for n,(t,m) in enumerate(rows,1):
        short=t['id'].split('-')[0]+'-'+t['id'].split('-')[1]
        hint=re.sub(r'\s+',' ',t['last'])[:160]
        out.append(f"{n}. **{short}** [{t['project']}] {t['title'][:90]}")
        out.append(f"   - last ({t['last_ts'][:10]}): {hint}")
        if m: out.append(f"   - memo: {', '.join(m)}")
    out.append('')
dst=HOME/'Projects/chief-of-operations/state/steve-todo.md'; dst.write_text('\n'.join(out)+'\n')
print(dst); print({g[2:]:len(v) for g,v in sorted(groups.items())})