import sys import httpx from datetime import datetime, timezone def format_timestamp(ts): try: ts = ts.replace("Z", "+00:00") dt = datetime.fromisoformat(ts) dt = dt.astimezone(timezone.utc) return dt.strftime("%a %b %d %H:%M:%S UTC %Y") except Exception: return ts def resolve_handle(handle): if handle.startswith("did:"): return handle response = httpx.get( "https://bsky.social/xrpc/com.atproto.identity.resolveHandle", params={"handle": handle} ) if response.status_code != 200: raise Exception(f"Could not resolve handle: {handle}") return response.json().get("did") def get_pds_for_did(did): response = httpx.get(f"https://plc.directory/{did}") response.raise_for_status() doc = response.json() for service in doc.get("service", []): if service.get("id") == "#atproto_pds": return service.get("serviceEndpoint") raise Exception(f"No PDS found for {did}") if len(sys.argv) < 2: print("Usage: python3 plan_read.py ") sys.exit(1) target = sys.argv[1] print(f"fingering {target}...\n") did = resolve_handle(target) pds = get_pds_for_did(did) response = httpx.get( f"{pds}/xrpc/com.atproto.repo.getRecord", params={"repo": did, "collection": "io.atplan.plan", "rkey": "self"} ) if response.status_code != 200: print(f"No .plan found for {target}") print(f"Status: {response.status_code}") print(f"Detail: {response.text}") else: p = response.json().get("value", {}) print(f"{'─' * 50}") if p.get('displayName'): print(f" Name: {p['displayName']}") print(f" Handle: {target}") if p.get('status'): print(f" Status: {p['status']}") if p.get('project'): print(f" Project: {p['project']}") if p.get('url'): print(f" URL: {p['url']}") print(f" Updated: {format_timestamp(p['updatedAt'])}") print(f"{'─' * 50}") print() print(p.get('text', '')) print()