Add streak viewer - streak.py: Unified view of all streaks (habits, journal, notes, time) - 34 tools!
This commit is contained in:
@ -24,6 +24,11 @@
|
||||
"value": 33.0,
|
||||
"timestamp": "2026-01-30T23:58:26.472974",
|
||||
"note": "Past midnight"
|
||||
},
|
||||
{
|
||||
"value": 34.0,
|
||||
"timestamp": "2026-01-30T23:58:58.553542",
|
||||
"note": "Last before midnight!"
|
||||
}
|
||||
],
|
||||
"created": "2026-01-30T23:54:10.266015"
|
||||
|
||||
136
tools/streak.py
Executable file
136
tools/streak.py
Executable file
@ -0,0 +1,136 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
streak - View all streaks across tools
|
||||
|
||||
Unified view of habit streaks, journal streaks, etc.
|
||||
"""
|
||||
|
||||
import json
|
||||
from datetime import datetime, timedelta
|
||||
from pathlib import Path
|
||||
|
||||
WORKSPACE = Path("/home/wdjones/.openclaw/workspace")
|
||||
|
||||
def load_json(path: Path):
|
||||
if path.exists():
|
||||
try:
|
||||
with open(path) as f:
|
||||
return json.load(f)
|
||||
except:
|
||||
pass
|
||||
return {}
|
||||
|
||||
def check_date_exists(data: dict | list, date: str, key: str = None) -> bool:
|
||||
"""Check if an entry exists for a date."""
|
||||
if isinstance(data, dict):
|
||||
if key:
|
||||
return date in data.get(key, {})
|
||||
return date in data
|
||||
return False
|
||||
|
||||
def calculate_streak(check_func) -> int:
|
||||
"""Calculate a streak based on a check function."""
|
||||
streak = 0
|
||||
date = datetime.now()
|
||||
|
||||
while True:
|
||||
date_str = date.strftime("%Y-%m-%d")
|
||||
if check_func(date_str):
|
||||
streak += 1
|
||||
date -= timedelta(days=1)
|
||||
else:
|
||||
break
|
||||
|
||||
return streak
|
||||
|
||||
def get_habit_streak(habit_name: str) -> int:
|
||||
"""Get streak for a habit."""
|
||||
data = load_json(WORKSPACE / "data" / "habits.json")
|
||||
log = data.get('log', {})
|
||||
|
||||
def check(date):
|
||||
return habit_name in log.get(date, [])
|
||||
|
||||
return calculate_streak(check)
|
||||
|
||||
def get_journal_streak() -> int:
|
||||
"""Get journal writing streak."""
|
||||
journal_dir = WORKSPACE / "journal"
|
||||
if not journal_dir.exists():
|
||||
return 0
|
||||
|
||||
def check(date):
|
||||
year, month, day = date.split('-')
|
||||
path = journal_dir / year / month / f"{date}.json"
|
||||
if path.exists():
|
||||
data = load_json(path)
|
||||
return len(data.get('entries', [])) > 0
|
||||
return False
|
||||
|
||||
return calculate_streak(check)
|
||||
|
||||
def get_notes_streak() -> int:
|
||||
"""Get daily notes streak."""
|
||||
memory_dir = WORKSPACE / "memory"
|
||||
if not memory_dir.exists():
|
||||
return 0
|
||||
|
||||
def check(date):
|
||||
path = memory_dir / f"{date}.md"
|
||||
return path.exists()
|
||||
|
||||
return calculate_streak(check)
|
||||
|
||||
def get_time_tracking_streak() -> int:
|
||||
"""Get time tracking streak."""
|
||||
data = load_json(WORKSPACE / "data" / "timetrack.json")
|
||||
entries = data.get('entries', [])
|
||||
|
||||
dates_tracked = set()
|
||||
for e in entries:
|
||||
date = e['start'][:10]
|
||||
dates_tracked.add(date)
|
||||
|
||||
def check(date):
|
||||
return date in dates_tracked
|
||||
|
||||
return calculate_streak(check)
|
||||
|
||||
def show_streaks():
|
||||
"""Show all streaks."""
|
||||
print("\n🔥 Streaks")
|
||||
print("=" * 40)
|
||||
|
||||
# Notes streak
|
||||
notes = get_notes_streak()
|
||||
print(f" 📝 Daily Notes: {notes} day{'s' if notes != 1 else ''}")
|
||||
|
||||
# Journal streak
|
||||
journal = get_journal_streak()
|
||||
print(f" 📔 Journal: {journal} day{'s' if journal != 1 else ''}")
|
||||
|
||||
# Time tracking streak
|
||||
time_track = get_time_tracking_streak()
|
||||
print(f" ⏱️ Time Tracking: {time_track} day{'s' if time_track != 1 else ''}")
|
||||
|
||||
# Habit streaks
|
||||
habits_data = load_json(WORKSPACE / "data" / "habits.json")
|
||||
habits = habits_data.get('habits', {})
|
||||
|
||||
if habits:
|
||||
print(f"\n 📊 Habits:")
|
||||
for name, info in habits.items():
|
||||
if info.get('active', True):
|
||||
streak = get_habit_streak(name)
|
||||
if streak > 0:
|
||||
print(f" {name}: {streak} day{'s' if streak != 1 else ''} 🔥")
|
||||
else:
|
||||
print(f" {name}: 0 days")
|
||||
|
||||
print()
|
||||
|
||||
def main():
|
||||
show_streaks()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
1
ws
1
ws
@ -49,6 +49,7 @@ COMMANDS = {
|
||||
'timer': ('tools/timer.py', 'Countdown and stopwatch'),
|
||||
'gen': ('tools/gen.py', 'Password, UUID, lorem, etc.'),
|
||||
'fortune': ('tools/fortune.py', 'Random wisdom'),
|
||||
'streak': ('tools/streak.py', 'View all streaks'),
|
||||
|
||||
# Projects
|
||||
'news': ('projects/news-feed/main.py', 'RSS news reader'),
|
||||
|
||||
Reference in New Issue
Block a user