Add advanced tools - dashboard.py: Web dashboard on localhost:8080 - briefing.py: Morning briefing generator - scaffold.py: Project scaffolding (python, node, script, docs, experiment) - watcher.py: File change monitor - focus.py: Pomodoro-style focus timer
This commit is contained in:
137
tools/focus.py
Executable file
137
tools/focus.py
Executable file
@ -0,0 +1,137 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Focus timer - simple pomodoro-style timer with logging.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import time
|
||||
import json
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
WORKSPACE = Path("/home/wdjones/.openclaw/workspace")
|
||||
LOG_FILE = WORKSPACE / "memory" / "focus-log.json"
|
||||
|
||||
def load_log() -> list:
|
||||
"""Load focus session log."""
|
||||
if LOG_FILE.exists():
|
||||
try:
|
||||
with open(LOG_FILE) as f:
|
||||
return json.load(f)
|
||||
except:
|
||||
return []
|
||||
return []
|
||||
|
||||
def save_log(log: list):
|
||||
"""Save focus session log."""
|
||||
LOG_FILE.parent.mkdir(parents=True, exist_ok=True)
|
||||
with open(LOG_FILE, 'w') as f:
|
||||
json.dump(log, f, indent=2)
|
||||
|
||||
def format_time(seconds: int) -> str:
|
||||
"""Format seconds as MM:SS."""
|
||||
mins, secs = divmod(seconds, 60)
|
||||
return f"{mins:02d}:{secs:02d}"
|
||||
|
||||
def timer(minutes: int, task: str = None):
|
||||
"""Run a focus timer."""
|
||||
total_seconds = minutes * 60
|
||||
remaining = total_seconds
|
||||
|
||||
start_time = datetime.now()
|
||||
print(f"\n🎯 Focus session started: {minutes} minutes")
|
||||
if task:
|
||||
print(f" Task: {task}")
|
||||
print()
|
||||
|
||||
try:
|
||||
while remaining > 0:
|
||||
print(f"\r ⏱️ {format_time(remaining)} remaining ", end='', flush=True)
|
||||
time.sleep(1)
|
||||
remaining -= 1
|
||||
|
||||
print(f"\r ✅ Session complete! ")
|
||||
print("\n🔔 Time's up! Take a break.\n")
|
||||
|
||||
# Log the session
|
||||
log = load_log()
|
||||
log.append({
|
||||
'start': start_time.isoformat(),
|
||||
'end': datetime.now().isoformat(),
|
||||
'duration_minutes': minutes,
|
||||
'task': task,
|
||||
'completed': True
|
||||
})
|
||||
save_log(log)
|
||||
|
||||
except KeyboardInterrupt:
|
||||
elapsed = total_seconds - remaining
|
||||
print(f"\r ⏸️ Stopped after {format_time(elapsed)} ")
|
||||
|
||||
if elapsed > 60: # Log if > 1 minute
|
||||
log = load_log()
|
||||
log.append({
|
||||
'start': start_time.isoformat(),
|
||||
'end': datetime.now().isoformat(),
|
||||
'duration_minutes': round(elapsed / 60, 1),
|
||||
'task': task,
|
||||
'completed': False
|
||||
})
|
||||
save_log(log)
|
||||
print(" Session logged (partial)")
|
||||
|
||||
def stats():
|
||||
"""Show focus statistics."""
|
||||
log = load_log()
|
||||
|
||||
if not log:
|
||||
print("No focus sessions logged yet.")
|
||||
return
|
||||
|
||||
today = datetime.now().strftime("%Y-%m-%d")
|
||||
today_sessions = [s for s in log if s['start'].startswith(today)]
|
||||
|
||||
total_minutes = sum(s['duration_minutes'] for s in log)
|
||||
today_minutes = sum(s['duration_minutes'] for s in today_sessions)
|
||||
completed = len([s for s in log if s.get('completed')])
|
||||
|
||||
print("\n📊 Focus Stats")
|
||||
print(f" Total sessions: {len(log)}")
|
||||
print(f" Completed: {completed}")
|
||||
print(f" Total time: {total_minutes:.0f} minutes ({total_minutes/60:.1f} hours)")
|
||||
print(f" Today: {len(today_sessions)} sessions, {today_minutes:.0f} minutes")
|
||||
|
||||
if today_sessions:
|
||||
print("\n Today's sessions:")
|
||||
for s in today_sessions[-5:]:
|
||||
start = s['start'][11:16]
|
||||
status = "✅" if s.get('completed') else "⏸️"
|
||||
task = s.get('task', '')[:30] or 'No task'
|
||||
print(f" {status} {start} - {s['duration_minutes']}min - {task}")
|
||||
print()
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage:")
|
||||
print(" focus.py <minutes> [task] - Start a focus session")
|
||||
print(" focus.py stats - Show statistics")
|
||||
print("\nExamples:")
|
||||
print(" focus.py 25 'Write documentation'")
|
||||
print(" focus.py 15")
|
||||
sys.exit(0)
|
||||
|
||||
if sys.argv[1] == 'stats':
|
||||
stats()
|
||||
return
|
||||
|
||||
try:
|
||||
minutes = int(sys.argv[1])
|
||||
except ValueError:
|
||||
print("Minutes must be a number")
|
||||
sys.exit(1)
|
||||
|
||||
task = ' '.join(sys.argv[2:]) if len(sys.argv) > 2 else None
|
||||
timer(minutes, task)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user