← 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())})