Add journal and backup tools - journal.py: Structured journaling with prompts (morning/evening) - backup.py: Workspace backup, restore, and data export - Updated ws CLI with new commands - 18 tools total now

This commit is contained in:
2026-01-30 23:40:49 -06:00
parent 6ee620e302
commit 3b053ce71c
4 changed files with 414 additions and 0 deletions

205
tools/journal.py Executable file
View File

@ -0,0 +1,205 @@
#!/usr/bin/env python3
"""
journal - Structured daily journaling
Guided prompts for daily reflection and growth.
"""
import json
import sys
from datetime import datetime, timedelta
from pathlib import Path
WORKSPACE = Path("/home/wdjones/.openclaw/workspace")
JOURNAL_DIR = WORKSPACE / "journal"
PROMPTS = {
'morning': [
"What am I grateful for today?",
"What would make today great?",
"What am I looking forward to?",
],
'evening': [
"What went well today?",
"What could have gone better?",
"What did I learn?",
"What am I grateful for?",
],
'weekly': [
"What were this week's wins?",
"What challenges did I face?",
"What do I want to focus on next week?",
"How am I progressing on my goals?",
],
}
def get_journal_path(date: datetime = None) -> Path:
"""Get the journal file path for a date."""
if date is None:
date = datetime.now()
year = date.strftime("%Y")
month = date.strftime("%m")
day = date.strftime("%d")
path = JOURNAL_DIR / year / month
path.mkdir(parents=True, exist_ok=True)
return path / f"{date.strftime('%Y-%m-%d')}.json"
def load_entry(date: datetime = None) -> dict:
"""Load a journal entry."""
path = get_journal_path(date)
if path.exists():
with open(path) as f:
return json.load(f)
return {
'date': (date or datetime.now()).strftime("%Y-%m-%d"),
'entries': [],
}
def save_entry(entry: dict, date: datetime = None):
"""Save a journal entry."""
path = get_journal_path(date)
with open(path, 'w') as f:
json.dump(entry, f, indent=2)
def morning():
"""Morning journal routine."""
print("\n🌅 Morning Journal")
print("=" * 40)
print(f"Date: {datetime.now().strftime('%A, %B %d, %Y')}\n")
entry = load_entry()
responses = []
for i, prompt in enumerate(PROMPTS['morning'], 1):
print(f"{i}. {prompt}")
response = input("").strip()
if response:
responses.append({'prompt': prompt, 'response': response})
print()
if responses:
entry['entries'].append({
'type': 'morning',
'time': datetime.now().isoformat(),
'responses': responses,
})
save_entry(entry)
print("✓ Morning journal saved")
def evening():
"""Evening journal routine."""
print("\n🌙 Evening Reflection")
print("=" * 40)
print(f"Date: {datetime.now().strftime('%A, %B %d, %Y')}\n")
entry = load_entry()
responses = []
for i, prompt in enumerate(PROMPTS['evening'], 1):
print(f"{i}. {prompt}")
response = input("").strip()
if response:
responses.append({'prompt': prompt, 'response': response})
print()
if responses:
entry['entries'].append({
'type': 'evening',
'time': datetime.now().isoformat(),
'responses': responses,
})
save_entry(entry)
print("✓ Evening reflection saved")
def quick(text: str):
"""Quick journal entry."""
entry = load_entry()
entry['entries'].append({
'type': 'note',
'time': datetime.now().isoformat(),
'text': text,
})
save_entry(entry)
print(f"✓ Journal entry saved")
def show(days_ago: int = 0):
"""Show a journal entry."""
date = datetime.now() - timedelta(days=days_ago)
entry = load_entry(date)
print(f"\n📔 Journal: {entry['date']}")
print("=" * 40)
if not entry['entries']:
print("No entries for this day")
return
for item in entry['entries']:
time = item['time'][11:16]
if item['type'] == 'note':
print(f"\n[{time}] 📝 {item['text']}")
elif item['type'] in ('morning', 'evening'):
emoji = '🌅' if item['type'] == 'morning' else '🌙'
print(f"\n[{time}] {emoji} {item['type'].title()}")
for resp in item.get('responses', []):
print(f" Q: {resp['prompt']}")
print(f" A: {resp['response']}")
print()
def stats():
"""Show journaling statistics."""
total = 0
streak = 0
current_streak = True
date = datetime.now()
for i in range(365):
check_date = date - timedelta(days=i)
entry = load_entry(check_date)
if entry['entries']:
total += 1
if current_streak:
streak += 1
else:
current_streak = False
print(f"\n📊 Journal Stats")
print("=" * 40)
print(f" Current streak: {streak} days")
print(f" Total entries: {total} (last 365 days)")
print()
def main():
if len(sys.argv) < 2:
print("Usage:")
print(" journal morning - Morning prompts")
print(" journal evening - Evening reflection")
print(" journal <text> - Quick entry")
print(" journal show [days] - Show entry (0=today)")
print(" journal stats - Statistics")
show(0)
return
cmd = sys.argv[1]
if cmd == 'morning':
morning()
elif cmd == 'evening':
evening()
elif cmd == 'show':
days = int(sys.argv[2]) if len(sys.argv) > 2 else 0
show(days)
elif cmd == 'stats':
stats()
else:
# Quick entry
text = ' '.join(sys.argv[1:])
quick(text)
if __name__ == "__main__":
main()