Skip to content

CG Commands API Reference

Git-like CLI for Claude Parser - Main orchestrator @SINGLE_SOURCE_TRUTH: Delegates to split command modules @LOC_ENFORCEMENT: <80 LOC by using sub-apps

Basic Commands

Show current session and project status

Source code in claude_parser/cli/cg_basic.py
@app.command()
def status():
    """Show current session and project status"""
    sessions = discover_all_sessions()
    if not sessions:
        console.print("No Claude sessions found", style="yellow")
        return
    current_session, files = load_latest_session(), discover_current_project_files()
    table = Table(show_header=True, header_style="bold blue")
    table.add_column("Status")
    table.add_column("Info")
    table.add_row("Sessions", f"{len(sessions)} found")
    table.add_row("Files", f"{len(files)} Claude files")
    if current_session:
        # Simple message count from dict
        messages = current_session.get('messages', [])
        table.add_row("Messages", f"{len(messages)} messages")

        # Find last file operation manually
        file_ops = [m for m in messages if m.get('toolUseResult') and 'filePath' in str(m.get('toolUseResult', {}))]
        if file_ops:
            last_op = file_ops[-1]
            table.add_row("Last file op", f"UUID: {last_op.get('uuid', 'unknown')[:8]}...")
        else:
            table.add_row("File ops", "No file operations found")
    console.print(table)

Show message history

Source code in claude_parser/cli/cg_basic.py
@app.command()
def log(limit: int = typer.Option(10, "--limit", "-n", help="Number of messages")):
    """Show message history"""
    current_session = load_latest_session()
    if not current_session:
        console.print("No current session found", style="yellow")
        return

    # Handle dict-based session
    messages = current_session.get('messages', [])
    if not messages:
        console.print("No messages found in session", style="yellow")
        return

    # Get last N messages using more-itertools
    display_messages = list(take(limit, reversed(messages))) if limit else messages

    # Print messages
    for msg in reversed(display_messages):
        msg_type = msg.get('type', 'unknown')
        content = str(msg.get('content', ''))[:100]
        console.print(f"[bold]{msg_type}[/bold]: {content}{'...' if len(str(msg.get('content', ''))) > 100 else ''}")

Restore Commands

Restore files (like git checkout) - 0 tokens!

Source code in claude_parser/cli/cg_restore.py
@app.command()
def checkout(target: Optional[str] = typer.Argument(None)):
    """Restore files (like git checkout) - 0 tokens!"""
    session = load_latest_session()
    if not session:
        console.print("No session found", style="red")
        return

    jsonl_path = session.get('metadata', {}).get('transcript_path')
    if not jsonl_path:
        console.print("No transcript path found in session", style="red")
        return

    if not target:
        console.print("Usage: cg checkout <file> or cg checkout <uuid>", style="yellow")
        return

    checkpoint = find_current_checkpoint(session)
    if not checkpoint:
        console.print("No checkpoint found", style="yellow")
        return

    # Check if it's a folder checkout
    if target.endswith('/'):
        restored = restore_folder_from_jsonl(jsonl_path, checkpoint['uuid'], target)
        if restored:
            console.print(f"✓ Restored {len(restored)} files from {target}", style="green")
            for f in restored:
                console.print(f"  - {f}", style="dim")
        else:
            console.print(f"No files found in {target}", style="yellow")

    elif '.' in target or Path(target).exists():
        # Single file restoration
        file_path = str(Path(target).resolve())
        if restore_file_from_jsonl(jsonl_path, checkpoint['uuid'], file_path):
            console.print(f"✓ Restored {target} from checkpoint", style="green")
        else:
            console.print(f"No previous version of {target} found", style="yellow")
    else:
        # UUID checkout - TODO
        console.print(f"Restoring to UUID {target}...", style="cyan")
        console.print(f"Full UUID checkout in development", style="yellow")

Reset to a previous state (like git reset)

Source code in claude_parser/cli/cg_reset.py
@app.command()
def reset(hard: bool = typer.Option(False, "--hard", help="Reset files to state"),
          target: Optional[str] = typer.Argument(None, help="UUID to reset to")):
    """Reset to a previous state (like git reset)"""
    if not target:
        console.print("Usage: cg reset [--hard] <uuid>", style="yellow")
        return

    session = load_latest_session()
    if not session:
        console.print("No session found", style="red")
        return

    if hard:
        # Hard reset - restore all files to that state
        console.print(f"Hard reset to {target[:8]}... - restoring files", style="cyan")
        jsonl_path = session.get('metadata', {}).get('transcript_path')
        if not jsonl_path:
            console.print("No transcript path found", style="red")
            return
        # TODO: Implement full state restoration
        console.print(f"Would restore all files to state at {target[:8]}...", style="yellow")
    else:
        # Soft reset - just move pointer
        console.print(f"Soft reset to {target[:8]}... (pointer only)", style="cyan")
        console.print("Checkpoint updated (soft reset)", style="green")

Revert a specific change (like git revert)

Source code in claude_parser/cli/cg_reset.py
@app.command()
def revert(target: str = typer.Argument(..., help="UUID to revert")):
    """Revert a specific change (like git revert)"""
    session = load_latest_session()
    if not session:
        console.print("No session found", style="red")
        return

    console.print(f"Reverting changes from {target[:8]}...", style="cyan")

    # Find the message at this UUID in the messages list
    messages = session.get('messages', [])
    message = next((m for m in messages if str(m.get('uuid', '')).startswith(target)), None)

    if message:
        console.print(f"Found change: {message.get('type', 'unknown')}", style="cyan")
        # TODO: Implement actual revert logic
        console.print(f"Would revert changes from {target[:8]}...", style="yellow")
    else:
        console.print(f"UUID {target[:8]}... not found", style="red")

Advanced Commands

Find files in any message (like git log --all --grep)

Source code in claude_parser/cli/cg_advanced.py
@app.command()
def find(pattern: str = typer.Argument(..., help="Pattern to search for")):
    """Find files in any message (like git log --all --grep)"""
    files = discover_current_project_files()
    if not files:
        console.print("No Claude sessions found", style="yellow")
        return

    jsonl_paths = [str(f) for f in files]
    results = find_queries.find_files(pattern, jsonl_paths)

    if not results:
        console.print(f"No files matching '{pattern}' found", style="yellow")
        return

    table = Table(show_header=True, header_style="bold blue")
    table.add_column("UUID", style="cyan", width=12)
    table.add_column("File", style="green")
    table.add_column("Time", style="dim")
    table.add_column("Tool", style="yellow")

    for uuid, file_path, timestamp, tool in results[:20]:
        table.add_row(str(uuid)[:8] + "...", file_path, str(timestamp)[:19], tool)

    console.print(table)
    if len(results) > 20:
        console.print(f"\n... and {len(results)-20} more results", style="dim")

Show who last modified file (like git blame)

Source code in claude_parser/cli/cg_advanced.py
@app.command()
def blame(file: str = typer.Argument(..., help="File to blame")):
    """Show who last modified file (like git blame)"""
    files = discover_current_project_files()
    if not files:
        console.print("No Claude sessions found", style="yellow")
        return

    jsonl_paths = [str(f) for f in files]
    results = blame_queries.blame_file(file, jsonl_paths)

    if not results:
        console.print(f"No modifications found for '{file}'", style="yellow")
        return

    uuid, timestamp, tool, tool_input = results[0]
    console.print(f"\nLast modified by:", style="bold")
    console.print(f"  UUID: {uuid[:8]}...", style="cyan")
    console.print(f"  Time: {timestamp}", style="dim")
    console.print(f"  Tool: {tool}", style="yellow")

Reflog Commands

Show all operations history (like git reflog)

Source code in claude_parser/cli/cg_reflog.py
@app.command()
def reflog(limit: int = typer.Option(20, "--limit", "-n", help="Number of entries")):
    """Show all operations history (like git reflog)"""
    files = discover_current_project_files()
    if not files:
        console.print("No Claude sessions found", style="yellow")
        return

    jsonl_paths = [str(f) for f in files]
    results = reflog_queries.get_reflog(jsonl_paths, limit)

    if not results:
        console.print("No operations found", style="yellow")
        return

    for uuid, timestamp, tool, file_path, msg_type in results:
        # Format based on operation type
        if file_path:
            console.print(f"{str(uuid)[:8]} {tool}: {file_path}", style="green")
        elif tool:
            console.print(f"{str(uuid)[:8]} {tool}", style="yellow")
        else:
            console.print(f"{str(uuid)[:8]} {msg_type}", style="dim")

Show details of specific message (like git show)

Source code in claude_parser/cli/cg_reflog.py
@app.command()
def show(uuid: str = typer.Argument(..., help="UUID to show")):
    """Show details of specific message (like git show)"""
    session = load_latest_session()
    if not session:
        console.print("No session found", style="red")
        return

    # Search through messages directly
    found_message = None
    for msg in session['messages']:
        if str(msg.get('uuid', '')).startswith(uuid):
            found_message = msg
            break

    if not found_message:
        console.print(f"UUID {uuid} not found", style="red")
        return

    # Display message details
    console.print(f"\n[bold]Message {uuid[:8]}...[/bold]")
    console.print(f"Type: {found_message.get('type', 'unknown')}", style="yellow")
    console.print(f"Time: {found_message.get('timestamp', 'unknown')}", style="dim")

    if 'toolUseResult' in found_message:
        result_data = found_message['toolUseResult']
        if isinstance(result_data, str):
            import json
            try:
                result = json.loads(result_data)
                console.print(f"Tool: {result.get('type', 'N/A')}", style="cyan")
                if 'filePath' in result:
                    console.print(f"File: {result['filePath']}", style="green")
                if 'content' in result:
                    console.print("\nFile Content:", style="bold")
                    content = result['content']
                    console.print(content[:500] + "..." if len(content) > 500 else content)
            except json.JSONDecodeError:
                console.print(f"Tool Result: {result_data}", style="cyan")