UNPKG

create-ai-chat-context-experimental

Version:

Phase 2: TypeScript rewrite - AI Chat Context & Memory System with conversation extraction and AICF format support (powered by aicf-core v2.1.0).

198 lines 7.57 kB
"use strict"; /** * This file is part of create-ai-chat-context-experimental. * Licensed under the GNU Affero General Public License v3.0 or later (AGPL-3.0-or-later). * See LICENSE file for details. */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ClaudeDesktopParser = void 0; /** * Claude Desktop Parser * Extracts conversation data from Claude Desktop SQLite database * Phase 5.5b: October 2025 * * Parses SQLite database from ~/Library/Application Support/Claude/ * Extracts conversations, messages, and attachments */ const better_sqlite3_1 = __importDefault(require("better-sqlite3")); const crypto_1 = require("crypto"); const index_js_1 = require("../types/index.js"); const MessageBuilder_js_1 = require("../utils/MessageBuilder.js"); const ErrorUtils_js_1 = require("../utils/ErrorUtils.js"); /** * Parse Claude Desktop SQLite database * Converts SQLite messages to standard Message format */ class ClaudeDesktopParser { /** * Parse Claude Desktop database * * @param dbPath - Path to Claude Desktop database file * @returns Result with Message[] or error */ parse(dbPath) { let db = null; try { // Open database db = new better_sqlite3_1.default(dbPath, { readonly: true }); // Get all conversations const conversations = this.getConversations(db); if (!conversations.ok) { return conversations; } // Extract messages from all conversations const allMessages = []; for (const conversation of conversations.value) { const messagesResult = this.getConversationMessages(db, conversation.id); if (messagesResult.ok) { allMessages.push(...messagesResult.value); } } return (0, index_js_1.Ok)(allMessages); } catch (error) { return (0, index_js_1.Err)((0, ErrorUtils_js_1.handleError)(error, 'Failed to parse Claude Desktop database')); } finally { if (db) { try { db.close(); } catch { // Ignore close errors } } } } /** * Get all conversations from database * * @param db - SQLite database connection * @returns Result with Conversation[] or error */ getConversations(db) { try { // Try different possible table names const tableNames = ['conversations', 'chats', 'chat_conversations']; for (const tableName of tableNames) { try { const stmt = db.prepare(`SELECT * FROM ${tableName} LIMIT 1`); stmt.get(); // Table exists, use it const rows = db .prepare(`SELECT * FROM ${tableName}`) .all(); return (0, index_js_1.Ok)(rows); } catch { // Table doesn't exist, try next continue; } } // No conversations table found return (0, index_js_1.Ok)([]); } catch (error) { const message = error instanceof Error ? error.message : 'Unknown error'; return (0, index_js_1.Err)(new index_js_1.ExtractionError(`Failed to get conversations: ${message}`, error)); } } /** * Get messages for a specific conversation * * @param db - SQLite database connection * @param conversationId - Conversation ID * @returns Result with Message[] or error */ getConversationMessages(db, conversationId) { try { // Try different possible table names const tableNames = ['messages', 'chat_messages', 'conversation_messages']; let messages = []; let found = false; for (const tableName of tableNames) { try { const stmt = db.prepare(`SELECT * FROM ${tableName} WHERE conversation_id = ? LIMIT 1`); stmt.get(conversationId); // Table exists and has data, use it messages = db .prepare(`SELECT * FROM ${tableName} WHERE conversation_id = ? ORDER BY created_at ASC`) .all(conversationId); found = true; break; } catch { // Table doesn't exist or query failed, try next continue; } } if (!found) { return (0, index_js_1.Ok)([]); } // Convert to Message format const result = []; for (const msg of messages) { try { const content = this.extractContent(msg.content); if (content && content.length > 0) { const id = msg.id || `claude-desktop-${conversationId}-${(0, crypto_1.randomUUID)()}`; const message = MessageBuilder_js_1.MessageBuilder.createWithPlatform({ id, conversationId, timestamp: msg.created_at, role: msg.role === 'assistant' ? 'assistant' : 'user', content, platform: 'claude-desktop', extractedFrom: 'claude-desktop-sqlite', messageType: msg.role === 'assistant' ? 'ai_response' : 'user_request', rawLength: msg.content.length, }); result.push(message); } } catch { // Skip malformed messages continue; } } return (0, index_js_1.Ok)(result); } catch (error) { const message = error instanceof Error ? error.message : 'Unknown error'; return (0, index_js_1.Err)(new index_js_1.ExtractionError(`Failed to get conversation messages: ${message}`, error)); } } /** * Extract content from Claude Desktop message * Handles string and structured content * * @param content - Message content (string or JSON) * @returns Extracted text content */ extractContent(content) { if (typeof content === 'string') { return content.trim(); } if (typeof content === 'object' && content !== null) { // Handle structured content const obj = content; if (typeof obj['text'] === 'string') { return obj['text'].trim(); } if (typeof obj['message'] === 'string') { return obj['message'].trim(); } if (typeof obj['content'] === 'string') { return obj['content'].trim(); } // Fallback: stringify the object return JSON.stringify(content); } return ''; } } exports.ClaudeDesktopParser = ClaudeDesktopParser; //# sourceMappingURL=ClaudeDesktopParser.js.map