#!/usr/bin/env python3 """ today - Comprehensive daily overview Combines tasks, habits, time tracking, notes, and captures into one view. """ import json from datetime import datetime from pathlib import Path WORKSPACE = Path("/home/wdjones/.openclaw/workspace") def load_json(path: Path) -> dict | list: """Load JSON file safely.""" if path.exists(): try: with open(path) as f: return json.load(f) except: pass return {} if str(path).endswith('json') else [] def get_time_tracking(): """Get today's time tracking.""" data = load_json(WORKSPACE / "data" / "timetrack.json") today = datetime.now().strftime("%Y-%m-%d") entries = [e for e in data.get('entries', []) if e['start'].startswith(today)] current = data.get('current') total_mins = sum(e['duration_min'] for e in entries) return { 'current': current, 'entries': entries, 'total_mins': total_mins, } def get_habits(): """Get today's habit status.""" data = load_json(WORKSPACE / "data" / "habits.json") today = datetime.now().strftime("%Y-%m-%d") habits = data.get('habits', {}) done = data.get('log', {}).get(today, []) active = [(name, name in done) for name, info in habits.items() if info.get('active', True)] return { 'habits': active, 'done': len([h for h in active if h[1]]), 'total': len(active), } def get_captures(): """Get unprocessed captures.""" data = load_json(WORKSPACE / "inbox" / "captures.json") if isinstance(data, list): return [c for c in data if not c.get('processed')] return [] def get_tasks(): """Get tasks from TASKS.md.""" tasks_file = WORKSPACE / "TASKS.md" if not tasks_file.exists(): return {'in_progress': [], 'waiting': [], 'inbox': []} result = {'in_progress': [], 'waiting': [], 'inbox': []} section = None with open(tasks_file) as f: for line in f: if "## Inbox" in line: section = 'inbox' elif "## In Progress" in line: section = 'in_progress' elif "## Waiting" in line: section = 'waiting' elif "## Done" in line: section = None elif section and line.strip().startswith("- [ ]"): task = line.strip()[6:].strip() result[section].append(task) return result def get_notes(): """Get today's notes.""" today = datetime.now().strftime("%Y-%m-%d") notes_file = WORKSPACE / "memory" / f"{today}.md" if not notes_file.exists(): return None content = notes_file.read_text() lines = [l for l in content.split('\n') if l.strip() and not l.startswith('#')] return lines def format_duration(mins: float) -> str: """Format minutes as human readable.""" if mins < 60: return f"{mins:.0f}m" hours = int(mins // 60) m = int(mins % 60) return f"{hours}h {m}m" def main(): now = datetime.now() print() print("ā•”" + "═" * 50 + "ā•—") print(f"ā•‘ šŸ–¤ Today: {now.strftime('%A, %B %d, %Y'):^38} ā•‘") print(f"ā•‘ {now.strftime('%H:%M'):^48} ā•‘") print("ā•š" + "═" * 50 + "ā•") # Time tracking time_data = get_time_tracking() print(f"\nā±ļø Time Tracked: {format_duration(time_data['total_mins'])}") if time_data['current']: c = time_data['current'] print(f" └─ Currently: {c['task'][:35]}") # Habits habits = get_habits() if habits['total'] > 0: print(f"\nāœ… Habits: {habits['done']}/{habits['total']}") for name, done in habits['habits']: status = "āœ“" if done else "ā—‹" print(f" {status} {name}") # Tasks tasks = get_tasks() in_progress = len(tasks['in_progress']) waiting = len(tasks['waiting']) inbox = len(tasks['inbox']) if in_progress + waiting + inbox > 0: print(f"\nšŸ“‹ Tasks: {in_progress} active, {waiting} waiting, {inbox} inbox") for task in tasks['in_progress'][:3]: print(f" → {task[:40]}") # Captures captures = get_captures() if captures: print(f"\nšŸ“„ Inbox: {len(captures)} items") for cap in captures[:3]: emoji = {'idea': 'šŸ’”', 'task': 'āœ…', 'link': 'šŸ”—'}.get(cap.get('type'), 'šŸ“') print(f" {emoji} {cap['content'][:35]}...") # Notes notes = get_notes() if notes: print(f"\nšŸ“ Notes: {len(notes)} entries today") # Quick actions print("\n" + "─" * 52) print("Quick: ws habits check | ws track start ") print(" ws cap | ws note ") print() if __name__ == "__main__": main()