#!/usr/bin/env python3 """ Export session data for sharing or archiving. Usage: python3 session-export.py [--format json|markdown] [--output FILE] [session_id] """ import argparse import json import sys from datetime import datetime from pathlib import Path from typing import Dict, List, Optional CLAUDE_DIR = Path.home() / ".claude" HISTORY_DIR = CLAUDE_DIR / "state" / "personal-assistant" / "history" MEMORY_DIR = CLAUDE_DIR / "state" / "personal-assistant" / "memory" def load_json(path: Path) -> Optional[Dict]: """Load JSON file safely.""" try: with open(path) as f: return json.load(f) except (FileNotFoundError, json.JSONDecodeError): return None def get_session(session_id: Optional[str] = None) -> Optional[Dict]: """Get a specific session or the most recent one.""" index = load_json(HISTORY_DIR / "index.json") if not index or "sessions" not in index: return None sessions = index["sessions"] if not sessions: return None if session_id: # Find by ID prefix for s in sessions: if s.get("id", "").startswith(session_id): return s return None else: # Return most recent return sessions[-1] def get_memory_items(session_id: str) -> Dict[str, List]: """Get memory items from a specific session.""" result = { "preferences": [], "decisions": [], "projects": [], "facts": [] } for category in result.keys(): data = load_json(MEMORY_DIR / f"{category}.json") if data and "items" in data: for item in data["items"]: if item.get("session", "") == session_id: result[category].append(item) return result def export_json(session: Dict, memory: Dict) -> str: """Export as JSON.""" export = { "exported_at": datetime.now().isoformat(), "session": session, "memory_items": memory } return json.dumps(export, indent=2) def export_markdown(session: Dict, memory: Dict) -> str: """Export as Markdown.""" lines = [ f"# Session Export", f"", f"**Exported:** {datetime.now().strftime('%Y-%m-%d %H:%M')}", f"", f"## Session Details", f"", f"- **ID:** {session.get('id', 'unknown')}", f"- **Date:** {session.get('date', 'unknown')}", f"- **Summarized:** {'Yes' if session.get('summarized') else 'No'}", f"", ] # Topics topics = session.get("topics", []) if topics: lines.append("### Topics") lines.append("") for topic in topics: lines.append(f"- {topic}") lines.append("") # Summary summary = session.get("summary", "") if summary: lines.append("### Summary") lines.append("") lines.append(summary) lines.append("") # Memory items has_memory = any(items for items in memory.values()) if has_memory: lines.append("## Memory Items Created") lines.append("") for category, items in memory.items(): if items: lines.append(f"### {category.title()}") lines.append("") for item in items: content = item.get("content", "") context = item.get("context", "") lines.append(f"- {content}") if context: lines.append(f" - *Context: {context}*") lines.append("") return "\n".join(lines) def list_sessions(limit: int = 10): """List recent sessions for export.""" index = load_json(HISTORY_DIR / "index.json") if not index or "sessions" not in index: print("No sessions found.") return sessions = index["sessions"][-limit:] print(f"\nšŸ“‹ Recent Sessions (showing {len(sessions)})\n") print(f"{'ID':<12} {'Date':<12} {'Summarized':<12} {'Topics'}") print("-" * 60) for session in reversed(sessions): sid = session.get("id", "unknown")[:10] date = session.get("date", "unknown")[:10] summarized = "āœ“" if session.get("summarized", False) else "ā—‹" topics = ", ".join(session.get("topics", [])[:2]) if len(session.get("topics", [])) > 2: topics += "..." print(f"{sid:<12} {date:<12} {summarized:<12} {topics}") print(f"\nExport with: python3 session-export.py ") print("") def main(): parser = argparse.ArgumentParser(description="Export session data") parser.add_argument("session_id", nargs="?", help="Session ID to export") parser.add_argument("--format", "-f", choices=["json", "markdown", "md"], default="markdown", help="Export format (default: markdown)") parser.add_argument("--output", "-o", type=str, help="Output file (default: stdout)") parser.add_argument("--list", "-l", action="store_true", help="List recent sessions") parser.add_argument("--limit", "-n", type=int, default=10, help="Number of sessions to list (default: 10)") args = parser.parse_args() if args.list: list_sessions(args.limit) return 0 # Get session session = get_session(args.session_id) if not session: if args.session_id: print(f"Session '{args.session_id}' not found.") else: print("No sessions found. Run some sessions first.") return 1 # Get memory items for this session memory = get_memory_items(session.get("id", "")) # Export if args.format in ["markdown", "md"]: content = export_markdown(session, memory) else: content = export_json(session, memory) # Output if args.output: output_path = Path(args.output) output_path.write_text(content) print(f"Exported to: {output_path}") else: print(content) return 0 if __name__ == "__main__": sys.exit(main())