154 lines
4.9 KiB
Python
154 lines
4.9 KiB
Python
|
|
#!/usr/bin/env python3
|
||
|
|
"""
|
||
|
|
Command-line tool to import data from .claude.json file.
|
||
|
|
|
||
|
|
Usage:
|
||
|
|
python import_claude_data.py [--file path/to/.claude.json] [--preview]
|
||
|
|
"""
|
||
|
|
|
||
|
|
import asyncio
|
||
|
|
import argparse
|
||
|
|
import sys
|
||
|
|
from pathlib import Path
|
||
|
|
|
||
|
|
from app.database.connection import async_session_maker, init_database
|
||
|
|
from app.api.importer import ClaudeJsonImporter
|
||
|
|
|
||
|
|
|
||
|
|
async def preview_import(file_path: str):
|
||
|
|
"""Preview what would be imported."""
|
||
|
|
print(f"🔍 Previewing import from: {file_path}")
|
||
|
|
print("=" * 50)
|
||
|
|
|
||
|
|
try:
|
||
|
|
import json
|
||
|
|
import os
|
||
|
|
|
||
|
|
if not os.path.exists(file_path):
|
||
|
|
print(f"❌ File not found: {file_path}")
|
||
|
|
return False
|
||
|
|
|
||
|
|
with open(file_path, 'r', encoding='utf-8') as f:
|
||
|
|
claude_data = json.load(f)
|
||
|
|
|
||
|
|
file_size_mb = round(os.path.getsize(file_path) / (1024 * 1024), 2)
|
||
|
|
|
||
|
|
print(f"📁 File size: {file_size_mb} MB")
|
||
|
|
print(f"🚀 Total Claude Code startups: {claude_data.get('numStartups', 0)}")
|
||
|
|
print(f"📅 First start time: {claude_data.get('firstStartTime', 'N/A')}")
|
||
|
|
print(f"📊 Prompt queue uses: {claude_data.get('promptQueueUseCount', 0)}")
|
||
|
|
|
||
|
|
if "projects" in claude_data:
|
||
|
|
projects = claude_data["projects"]
|
||
|
|
print(f"📂 Projects found: {len(projects)}")
|
||
|
|
|
||
|
|
# Show first few project paths
|
||
|
|
paths = list(projects.keys())[:5]
|
||
|
|
for path in paths:
|
||
|
|
history_count = len(projects[path].get("history", []))
|
||
|
|
print(f" • {path} ({history_count} history entries)")
|
||
|
|
|
||
|
|
if len(projects) > 5:
|
||
|
|
print(f" ... and {len(projects) - 5} more projects")
|
||
|
|
|
||
|
|
# Count total history entries
|
||
|
|
total_history = sum(len(proj.get("history", [])) for proj in projects.values())
|
||
|
|
print(f"💬 Total conversation history entries: {total_history}")
|
||
|
|
|
||
|
|
print("\n✅ Preview completed successfully!")
|
||
|
|
return True
|
||
|
|
|
||
|
|
except Exception as e:
|
||
|
|
print(f"❌ Preview failed: {e}")
|
||
|
|
return False
|
||
|
|
|
||
|
|
|
||
|
|
async def run_import(file_path: str):
|
||
|
|
"""Run the actual import process."""
|
||
|
|
print(f"📥 Starting import from: {file_path}")
|
||
|
|
print("=" * 50)
|
||
|
|
|
||
|
|
# Initialize database tables first
|
||
|
|
print("🔧 Initializing database...")
|
||
|
|
await init_database()
|
||
|
|
print("✅ Database initialized")
|
||
|
|
|
||
|
|
async with async_session_maker() as db:
|
||
|
|
try:
|
||
|
|
importer = ClaudeJsonImporter(db)
|
||
|
|
results = await importer.import_from_file(file_path)
|
||
|
|
|
||
|
|
print("🎉 Import completed successfully!")
|
||
|
|
print(f"📂 Projects imported: {results['projects_imported']}")
|
||
|
|
print(f"⏱️ Sessions estimated: {results['sessions_estimated']}")
|
||
|
|
print(f"💬 Conversations imported: {results['conversations_imported']}")
|
||
|
|
|
||
|
|
if results['errors']:
|
||
|
|
print(f"\n⚠️ Warnings/Errors ({len(results['errors'])}):")
|
||
|
|
for error in results['errors']:
|
||
|
|
print(f" • {error}")
|
||
|
|
|
||
|
|
print("\n🚀 You can now view your imported data at: http://localhost:8000")
|
||
|
|
return True
|
||
|
|
|
||
|
|
except Exception as e:
|
||
|
|
print(f"❌ Import failed: {e}")
|
||
|
|
return False
|
||
|
|
|
||
|
|
|
||
|
|
def main():
|
||
|
|
"""Main entry point."""
|
||
|
|
parser = argparse.ArgumentParser(
|
||
|
|
description="Import Claude Code data from .claude.json file",
|
||
|
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||
|
|
epilog="""
|
||
|
|
Examples:
|
||
|
|
python import_claude_data.py --preview
|
||
|
|
python import_claude_data.py --file ~/.claude.json
|
||
|
|
python import_claude_data.py --file ~/.claude.json --preview
|
||
|
|
"""
|
||
|
|
)
|
||
|
|
|
||
|
|
parser.add_argument(
|
||
|
|
"--file",
|
||
|
|
type=str,
|
||
|
|
default=None,
|
||
|
|
help="Path to .claude.json file (default: ~/.claude.json)"
|
||
|
|
)
|
||
|
|
|
||
|
|
parser.add_argument(
|
||
|
|
"--preview",
|
||
|
|
action="store_true",
|
||
|
|
help="Preview what would be imported without actually importing"
|
||
|
|
)
|
||
|
|
|
||
|
|
args = parser.parse_args()
|
||
|
|
|
||
|
|
# Determine file path
|
||
|
|
if args.file:
|
||
|
|
file_path = args.file
|
||
|
|
else:
|
||
|
|
file_path = str(Path.home() / ".claude.json")
|
||
|
|
|
||
|
|
print("🤖 Claude Code Project Tracker - Data Importer")
|
||
|
|
print("=" * 50)
|
||
|
|
|
||
|
|
if args.preview:
|
||
|
|
success = asyncio.run(preview_import(file_path))
|
||
|
|
else:
|
||
|
|
print("⚠️ This will import data into your Claude Code Project Tracker database.")
|
||
|
|
print(" Make sure the tracker server is not running during import.")
|
||
|
|
print()
|
||
|
|
|
||
|
|
confirm = input("Continue with import? (y/N): ").lower().strip()
|
||
|
|
if confirm != 'y':
|
||
|
|
print("Import cancelled.")
|
||
|
|
sys.exit(0)
|
||
|
|
|
||
|
|
success = asyncio.run(run_import(file_path))
|
||
|
|
|
||
|
|
sys.exit(0 if success else 1)
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
main()
|