Files
workspace/tools/capture.py

178 lines
5.1 KiB
Python
Executable File

#!/usr/bin/env python3
"""
capture - Quick thought capture
Quickly capture thoughts, tasks, ideas, and links.
They go to inbox for later processing.
"""
import json
import sys
from datetime import datetime
from pathlib import Path
WORKSPACE = Path("/home/wdjones/.openclaw/workspace")
CAPTURE_FILE = WORKSPACE / "inbox" / "captures.json"
TYPES = {
'thought': '💭',
'task': '',
'idea': '💡',
'link': '🔗',
'note': '📝',
'quote': '💬',
'question': '',
}
def load_captures() -> list:
"""Load captured items."""
CAPTURE_FILE.parent.mkdir(parents=True, exist_ok=True)
if CAPTURE_FILE.exists():
with open(CAPTURE_FILE) as f:
return json.load(f)
return []
def save_captures(captures: list):
"""Save captures."""
with open(CAPTURE_FILE, 'w') as f:
json.dump(captures, f, indent=2)
def capture(content: str, capture_type: str = 'note', tags: list = None):
"""Capture something quickly."""
captures = load_captures()
item = {
'id': len(captures) + 1,
'content': content,
'type': capture_type if capture_type in TYPES else 'note',
'tags': tags or [],
'captured': datetime.now().isoformat(),
'processed': False,
}
captures.append(item)
save_captures(captures)
emoji = TYPES.get(capture_type, '📝')
print(f"{emoji} Captured #{item['id']}: {content[:50]}...")
def list_captures(show_all: bool = False, type_filter: str = None):
"""List captured items."""
captures = load_captures()
if not show_all:
captures = [c for c in captures if not c.get('processed')]
if type_filter:
captures = [c for c in captures if c['type'] == type_filter]
if not captures:
print("📭 Inbox empty")
return
print(f"\n📥 Inbox ({len(captures)} items)")
print("=" * 50)
for item in captures:
emoji = TYPES.get(item['type'], '📝')
status = "" if item.get('processed') else " "
content = item['content'][:60]
if len(item['content']) > 60:
content += "..."
print(f"[{status}] #{item['id']:3} {emoji} {content}")
if item.get('tags'):
tags = ' '.join(f"#{t}" for t in item['tags'])
print(f" {tags}")
print()
def process_item(item_id: int):
"""Mark an item as processed."""
captures = load_captures()
for item in captures:
if item['id'] == item_id:
item['processed'] = True
save_captures(captures)
print(f"✓ Processed #{item_id}")
return
print(f"Item not found: #{item_id}")
def clear_processed():
"""Remove processed items."""
captures = load_captures()
unprocessed = [c for c in captures if not c.get('processed')]
removed = len(captures) - len(unprocessed)
save_captures(unprocessed)
print(f"✓ Removed {removed} processed items")
def export_markdown():
"""Export unprocessed items as markdown."""
captures = load_captures()
unprocessed = [c for c in captures if not c.get('processed')]
if not unprocessed:
print("Nothing to export")
return
# Group by type
by_type = {}
for item in unprocessed:
t = item['type']
if t not in by_type:
by_type[t] = []
by_type[t].append(item)
print("# Inbox Export")
print(f"*Exported: {datetime.now().strftime('%Y-%m-%d %H:%M')}*\n")
for type_name, items in sorted(by_type.items()):
emoji = TYPES.get(type_name, '📝')
print(f"## {emoji} {type_name.title()}s\n")
for item in items:
tags = ' '.join(f"`#{t}`" for t in item.get('tags', []))
print(f"- {item['content']} {tags}")
print()
def main():
if len(sys.argv) < 2:
print("Usage:")
print(" capture <text> - Quick capture")
print(" capture -t task <text> - Capture as task")
print(" capture -t idea <text> - Capture as idea")
print(" capture -t link <url> - Capture a link")
print(" capture list - Show inbox")
print(" capture list --all - Show all (incl. processed)")
print(" capture done <id> - Mark as processed")
print(" capture clear - Clear processed items")
print(" capture export - Export as markdown")
print("")
print(f"Types: {', '.join(TYPES.keys())}")
list_captures()
return
# Parse args
if sys.argv[1] == 'list':
show_all = '--all' in sys.argv
list_captures(show_all=show_all)
elif sys.argv[1] == 'done' and len(sys.argv) > 2:
process_item(int(sys.argv[2]))
elif sys.argv[1] == 'clear':
clear_processed()
elif sys.argv[1] == 'export':
export_markdown()
elif sys.argv[1] == '-t' and len(sys.argv) > 3:
capture_type = sys.argv[2]
content = ' '.join(sys.argv[3:])
capture(content, capture_type)
else:
content = ' '.join(sys.argv[1:])
capture(content)
if __name__ == "__main__":
main()