/** * Multi-pass JSONL Conversation Parser for Claude Code history. * * This parser reads conversation history from Claude Code's storage locations * (~/.claude/projects) and extracts structured data including messages, tool uses, * file edits, and thinking blocks. * * The parser handles two directory structures: * - Modern: ~/.claude/projects/{sanitized-path} * - Legacy: ~/.claude/projects/{original-project-name} * * It performs a multi-pass parsing approach: * 1. First pass: Extract conversations and messages * 2. Second pass: Link tool uses and results * 3. Third pass: Extract file edits from snapshots * 4. Fourth pass: Extract thinking blocks * * @example * ```typescript * const parser = new ConversationParser(); * const result = parser.parseProject('/path/to/project'); * console.error(`Parsed ${result.conversations.length} conversations`); * console.error(`Found ${result.messages.length} messages`); * console.error(`Extracted ${result.tool_uses.length} tool uses`); * ``` */ export interface ConversationMessage { type: string; uuid?: string; parentUuid?: string | null; sessionId?: string; timestamp?: string; isSidechain?: boolean; agentId?: string; userType?: string; cwd?: string; version?: string; gitBranch?: string; message?: unknown; requestId?: string; messageId?: string; snapshot?: unknown; summary?: string; leafUuid?: string; subtype?: string; level?: string; content?: string | unknown[]; error?: unknown; toolUseResult?: unknown; [key: string]: unknown; } export interface Conversation { id: string; project_path: string; source_type?: 'claude-code' | 'codex'; first_message_at: number; last_message_at: number; message_count: number; git_branch?: string; claude_version?: string; metadata: Record; created_at: number; updated_at: number; } export interface Message { id: string; conversation_id: string; parent_id?: string; message_type: string; role?: string; content?: string; timestamp: number; is_sidechain: boolean; agent_id?: string; request_id?: string; git_branch?: string; cwd?: string; metadata: Record; } export interface ToolUse { id: string; message_id: string; tool_name: string; tool_input: Record; timestamp: number; } export interface ToolResult { id: string; tool_use_id: string; message_id: string; content?: string; is_error: boolean; stdout?: string; stderr?: string; is_image: boolean; timestamp: number; } export interface FileEdit { id: string; conversation_id: string; file_path: string; message_id: string; backup_version?: number; backup_time?: number; snapshot_timestamp: number; metadata: Record; } export interface ThinkingBlock { id: string; message_id: string; thinking_content: string; signature?: string; timestamp: number; } /** * Information about a parsing error */ export interface ParseError { /** File path where error occurred */ file: string; /** Line number (1-based) */ line: number; /** Error message */ error: string; } /** * Result of parsing conversation history. * * Contains all extracted entities from conversation files. */ export interface ParseResult { /** Parsed conversations with metadata */ conversations: Conversation[]; /** All messages from conversations */ messages: Message[]; /** Tool invocations extracted from assistant messages */ tool_uses: ToolUse[]; /** Results from tool executions */ tool_results: ToolResult[]; /** File edit records from snapshots */ file_edits: FileEdit[]; /** Thinking blocks (Claude's internal reasoning) */ thinking_blocks: ThinkingBlock[]; /** Folders that were actually indexed */ indexed_folders?: string[]; /** Parsing errors encountered (bad JSON lines, etc.) */ parse_errors?: ParseError[]; } /** * Parser for Claude Code conversation history. * * Extracts structured data from JSONL conversation files stored in * ~/.claude/projects. Handles both modern and legacy naming conventions. */ export declare class ConversationParser { /** * Parse all conversations for a project. * * Searches for conversation files in Claude's storage directories and * parses them into structured entities. Supports filtering by session ID * and handles both modern and legacy directory naming conventions. * * @param projectPath - Absolute path to the project (used for folder lookup) * @param sessionId - Optional session ID to filter for a single conversation * @param projectIdentifier - Optional identifier to store as project_path * @param lastIndexedMs - Optional timestamp to skip unchanged files (mtime) * @returns ParseResult containing all extracted entities * * @example * ```typescript * const parser = new ConversationParser(); * * // Parse all conversations * const allResults = parser.parseProject('/Users/me/my-project'); * * // Parse specific session * const sessionResults = parser.parseProject('/Users/me/my-project', 'session-123'); * ``` */ parseProject(projectPath: string, sessionId?: string, projectIdentifier?: string, lastIndexedMs?: number): ParseResult; /** * Parse conversations across multiple project paths and merge results. * * @param projectPaths - Project paths to scan for conversation folders * @param sessionId - Optional session ID to filter for a single conversation * @param projectIdentifier - Optional identifier to store as project_path */ parseProjects(projectPaths: string[], sessionId?: string, projectIdentifier?: string, lastIndexedMs?: number): ParseResult; private mergeParseResults; /** * Parse conversations directly from a Claude projects folder. * * This method is used when you already have the path to the conversation * folder (e.g., ~/.claude/projects/-Users-me-my-project) rather than * a project path that needs to be converted. * * @param folderPath - Absolute path to the Claude projects folder * @param projectIdentifier - Optional identifier to use as project_path in records (defaults to folder path) * @returns ParseResult containing all extracted entities * * @example * ```typescript * const parser = new ConversationParser(); * const result = parser.parseFromFolder('~/.claude/projects/-Users-me-my-project'); * ``` */ parseFromFolder(folderPath: string, projectIdentifier?: string, lastIndexedMs?: number): ParseResult; /** * Parse conversations from a Claude projects folder using streaming. * * This async method uses line-by-line streaming to efficiently handle * large JSONL files without loading the entire file into memory. * Use this method for large conversation histories. * * @param folderPath - Absolute path to the Claude projects folder * @param projectIdentifier - Optional identifier to use as project_path in records * @param lastIndexedMs - Optional timestamp for incremental indexing (skip unchanged files) * @returns Promise containing all extracted entities * * @example * ```typescript * const parser = new ConversationParser(); * const result = await parser.parseFromFolderAsync('~/.claude/projects/-Users-me-my-project'); * ``` */ parseFromFolderAsync(folderPath: string, projectIdentifier?: string, lastIndexedMs?: number): Promise; /** * Parse a single .jsonl file using streaming (async). * * Uses readline interface with createReadStream to read the file * line by line, avoiding loading the entire file into memory. */ private parseFileAsync; /** * Parse a single .jsonl file */ private parseFile; /** * Pass 1: Extract conversation metadata */ private extractConversation; /** * Detect MCP tool usage in conversation messages */ private detectMcpUsage; /** * Pass 2: Extract individual messages */ private extractMessages; /** * Pass 3: Extract tool uses and results */ private extractToolCalls; /** * Pass 4: Extract file edits from snapshots */ private extractFileEdits; /** * Pass 5: Extract thinking blocks */ private extractThinkingBlocks; /** * Generate path variants to handle potential encoding differences. * * Claude Code may encode paths differently than expected: * - Hyphens in path components might become underscores * - Underscores might become hyphens * - Dots might become hyphens (legacy) * * This method generates multiple variants to try when searching for directories. * * @example * Input: "-Users-myid-GIT-projects-myProject" * Output: [ * "-Users-myid-GIT-projects-myProject", // Original * "-Users-myid-GIT_projects-myProject", // Hyphens in components -> underscores * "-Users-myid-GIT-projects-myProject", // Dots -> hyphens (legacy) * ] */ private generatePathVariants; /** * Extract text content from message */ private extractContent; } //# sourceMappingURL=ConversationParser.d.ts.map