Add goals, reading list, and people CRM - goals.py: Goal tracking with milestones and progress - reading.py: Reading list tracker (articles, books, papers) - people.py: Personal CRM for keeping notes on people - 21 tools total now
This commit is contained in:
151
tools/people.py
Executable file
151
tools/people.py
Executable file
@ -0,0 +1,151 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
people - Personal CRM / people notes
|
||||
|
||||
Keep notes about people you know.
|
||||
"""
|
||||
|
||||
import json
|
||||
import sys
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
WORKSPACE = Path("/home/wdjones/.openclaw/workspace")
|
||||
PEOPLE_FILE = WORKSPACE / "data" / "people.json"
|
||||
|
||||
def load_people() -> dict:
|
||||
"""Load people data."""
|
||||
PEOPLE_FILE.parent.mkdir(parents=True, exist_ok=True)
|
||||
if PEOPLE_FILE.exists():
|
||||
with open(PEOPLE_FILE) as f:
|
||||
return json.load(f)
|
||||
return {}
|
||||
|
||||
def save_people(data: dict):
|
||||
"""Save people data."""
|
||||
with open(PEOPLE_FILE, 'w') as f:
|
||||
json.dump(data, f, indent=2)
|
||||
|
||||
def add_person(name: str, context: str = None):
|
||||
"""Add a new person."""
|
||||
people = load_people()
|
||||
key = name.lower().replace(' ', '_')
|
||||
|
||||
if key in people:
|
||||
print(f"Person already exists: {name}")
|
||||
return
|
||||
|
||||
people[key] = {
|
||||
'name': name,
|
||||
'context': context,
|
||||
'added': datetime.now().isoformat(),
|
||||
'notes': [],
|
||||
'tags': [],
|
||||
'last_contact': None,
|
||||
}
|
||||
|
||||
save_people(people)
|
||||
print(f"👤 Added: {name}")
|
||||
|
||||
def add_note(name: str, note: str):
|
||||
"""Add a note about someone."""
|
||||
people = load_people()
|
||||
search = name.lower().replace(' ', '')
|
||||
|
||||
# Find by partial match (normalize spaces)
|
||||
matches = [k for k in people if search in k.replace('_', '') or search in people[k]['name'].lower().replace(' ', '')]
|
||||
if not matches:
|
||||
print(f"Person not found: {name}")
|
||||
return
|
||||
|
||||
key = matches[0]
|
||||
people[key]['notes'].append({
|
||||
'text': note,
|
||||
'date': datetime.now().isoformat(),
|
||||
})
|
||||
people[key]['last_contact'] = datetime.now().isoformat()
|
||||
|
||||
save_people(people)
|
||||
print(f"📝 Note added for {people[key]['name']}")
|
||||
|
||||
def show_person(name: str):
|
||||
"""Show info about a person."""
|
||||
people = load_people()
|
||||
search = name.lower().replace(' ', '')
|
||||
|
||||
# Find by partial match (normalize spaces)
|
||||
matches = [k for k in people if search in k.replace('_', '') or search in people[k]['name'].lower().replace(' ', '')]
|
||||
if not matches:
|
||||
print(f"Person not found: {name}")
|
||||
return
|
||||
|
||||
person = people[matches[0]]
|
||||
|
||||
print(f"\n👤 {person['name']}")
|
||||
print("=" * 40)
|
||||
|
||||
if person.get('context'):
|
||||
print(f"Context: {person['context']}")
|
||||
|
||||
if person.get('last_contact'):
|
||||
last = person['last_contact'][:10]
|
||||
print(f"Last contact: {last}")
|
||||
|
||||
if person['notes']:
|
||||
print(f"\n📝 Notes ({len(person['notes'])})")
|
||||
for note in person['notes'][-5:]:
|
||||
date = note['date'][:10]
|
||||
print(f" [{date}] {note['text'][:50]}")
|
||||
|
||||
print()
|
||||
|
||||
def list_people():
|
||||
"""List all people."""
|
||||
people = load_people()
|
||||
|
||||
if not people:
|
||||
print("No people yet. Add with: people add <name>")
|
||||
return
|
||||
|
||||
print(f"\n👥 People ({len(people)})")
|
||||
print("=" * 40)
|
||||
|
||||
for key, person in sorted(people.items()):
|
||||
notes = len(person['notes'])
|
||||
context = person.get('context', '')[:20]
|
||||
print(f" {person['name']:20} {notes} notes {context}")
|
||||
|
||||
print()
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
list_people()
|
||||
return
|
||||
|
||||
cmd = sys.argv[1]
|
||||
|
||||
if cmd == 'add' and len(sys.argv) > 2:
|
||||
name = sys.argv[2]
|
||||
context = ' '.join(sys.argv[3:]) if len(sys.argv) > 3 else None
|
||||
add_person(name, context)
|
||||
|
||||
elif cmd == 'note' and len(sys.argv) > 3:
|
||||
name = sys.argv[2]
|
||||
note = ' '.join(sys.argv[3:])
|
||||
add_note(name, note)
|
||||
|
||||
elif cmd == 'show' and len(sys.argv) > 2:
|
||||
show_person(sys.argv[2])
|
||||
|
||||
elif cmd == 'list':
|
||||
list_people()
|
||||
|
||||
else:
|
||||
print("Usage:")
|
||||
print(" people - List all")
|
||||
print(" people add <name> [context] - Add person")
|
||||
print(" people note <name> <text> - Add note")
|
||||
print(" people show <name> - Show person")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user