174 lines
5.1 KiB
Python
Executable File
174 lines
5.1 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
goals - Goal and project tracking with milestones
|
|
|
|
Track long-term goals and break them into actionable steps.
|
|
"""
|
|
|
|
import json
|
|
import sys
|
|
from datetime import datetime
|
|
from pathlib import Path
|
|
|
|
WORKSPACE = Path("/home/wdjones/.openclaw/workspace")
|
|
GOALS_FILE = WORKSPACE / "data" / "goals.json"
|
|
|
|
def load_goals() -> dict:
|
|
"""Load goals data."""
|
|
GOALS_FILE.parent.mkdir(parents=True, exist_ok=True)
|
|
if GOALS_FILE.exists():
|
|
with open(GOALS_FILE) as f:
|
|
return json.load(f)
|
|
return {'goals': []}
|
|
|
|
def save_goals(data: dict):
|
|
"""Save goals data."""
|
|
with open(GOALS_FILE, 'w') as f:
|
|
json.dump(data, f, indent=2)
|
|
|
|
def add_goal(title: str, description: str = "", deadline: str = None):
|
|
"""Add a new goal."""
|
|
data = load_goals()
|
|
|
|
goal = {
|
|
'id': len(data['goals']) + 1,
|
|
'title': title,
|
|
'description': description,
|
|
'deadline': deadline,
|
|
'created': datetime.now().isoformat(),
|
|
'status': 'active',
|
|
'milestones': [],
|
|
'progress': 0,
|
|
}
|
|
|
|
data['goals'].append(goal)
|
|
save_goals(data)
|
|
print(f"🎯 Goal #{goal['id']}: {title}")
|
|
|
|
def add_milestone(goal_id: int, title: str):
|
|
"""Add a milestone to a goal."""
|
|
data = load_goals()
|
|
|
|
for goal in data['goals']:
|
|
if goal['id'] == goal_id:
|
|
milestone = {
|
|
'id': len(goal['milestones']) + 1,
|
|
'title': title,
|
|
'done': False,
|
|
'created': datetime.now().isoformat(),
|
|
}
|
|
goal['milestones'].append(milestone)
|
|
save_goals(data)
|
|
print(f" ✓ Added milestone: {title}")
|
|
return
|
|
|
|
print(f"Goal not found: #{goal_id}")
|
|
|
|
def complete_milestone(goal_id: int, milestone_id: int):
|
|
"""Mark a milestone as complete."""
|
|
data = load_goals()
|
|
|
|
for goal in data['goals']:
|
|
if goal['id'] == goal_id:
|
|
for m in goal['milestones']:
|
|
if m['id'] == milestone_id:
|
|
m['done'] = True
|
|
m['completed'] = datetime.now().isoformat()
|
|
|
|
# Update progress
|
|
done = len([x for x in goal['milestones'] if x['done']])
|
|
total = len(goal['milestones'])
|
|
goal['progress'] = int(done / total * 100) if total > 0 else 0
|
|
|
|
save_goals(data)
|
|
print(f" ✓ Completed: {m['title']}")
|
|
print(f" Progress: {goal['progress']}%")
|
|
return
|
|
|
|
print("Milestone not found")
|
|
|
|
def show_goals(show_all: bool = False):
|
|
"""Display all goals."""
|
|
data = load_goals()
|
|
|
|
goals = data['goals']
|
|
if not show_all:
|
|
goals = [g for g in goals if g['status'] == 'active']
|
|
|
|
if not goals:
|
|
print("No active goals. Add one with: goals add <title>")
|
|
return
|
|
|
|
print(f"\n🎯 Goals ({len(goals)})")
|
|
print("=" * 50)
|
|
|
|
for goal in goals:
|
|
status = "✅" if goal['status'] == 'completed' else "🔵"
|
|
bar = "█" * (goal['progress'] // 10) + "░" * (10 - goal['progress'] // 10)
|
|
|
|
print(f"\n{status} #{goal['id']} {goal['title']}")
|
|
print(f" [{bar}] {goal['progress']}%")
|
|
|
|
if goal.get('deadline'):
|
|
print(f" 📅 Deadline: {goal['deadline']}")
|
|
|
|
if goal['milestones']:
|
|
for m in goal['milestones']:
|
|
check = "✓" if m['done'] else "○"
|
|
print(f" {check} {m['title']}")
|
|
|
|
print()
|
|
|
|
def complete_goal(goal_id: int):
|
|
"""Mark a goal as completed."""
|
|
data = load_goals()
|
|
|
|
for goal in data['goals']:
|
|
if goal['id'] == goal_id:
|
|
goal['status'] = 'completed'
|
|
goal['progress'] = 100
|
|
goal['completed'] = datetime.now().isoformat()
|
|
save_goals(data)
|
|
print(f"🎉 Goal completed: {goal['title']}")
|
|
return
|
|
|
|
print(f"Goal not found: #{goal_id}")
|
|
|
|
def main():
|
|
if len(sys.argv) < 2:
|
|
show_goals()
|
|
return
|
|
|
|
cmd = sys.argv[1]
|
|
|
|
if cmd == 'add' and len(sys.argv) > 2:
|
|
title = ' '.join(sys.argv[2:])
|
|
add_goal(title)
|
|
|
|
elif cmd == 'milestone' and len(sys.argv) > 3:
|
|
goal_id = int(sys.argv[2])
|
|
title = ' '.join(sys.argv[3:])
|
|
add_milestone(goal_id, title)
|
|
|
|
elif cmd == 'done' and len(sys.argv) > 3:
|
|
goal_id = int(sys.argv[2])
|
|
milestone_id = int(sys.argv[3])
|
|
complete_milestone(goal_id, milestone_id)
|
|
|
|
elif cmd == 'complete' and len(sys.argv) > 2:
|
|
complete_goal(int(sys.argv[2]))
|
|
|
|
elif cmd == 'list':
|
|
show_goals(show_all='--all' in sys.argv)
|
|
|
|
else:
|
|
print("Usage:")
|
|
print(" goals - Show active goals")
|
|
print(" goals add <title> - Add new goal")
|
|
print(" goals milestone <id> <text> - Add milestone")
|
|
print(" goals done <goal> <milestone> - Complete milestone")
|
|
print(" goals complete <id> - Complete goal")
|
|
|
|
if __name__ == "__main__":
|
|
main()
|