Add daily dashboard, wisdom, and system monitor - today.py: Comprehensive daily overview combining all tools - wisdom.py: Quotes and wisdom collection with daily feature - sysmon.py: System resource monitor (CPU, memory, disk) - Updated ws CLI with new commands
This commit is contained in:
160
tools/today.py
Executable file
160
tools/today.py
Executable file
@ -0,0 +1,160 @@
|
||||
#!/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 <name> | ws track start <task>")
|
||||
print(" ws cap <thought> | ws note <text>")
|
||||
print()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user