/**
 * Graph-based memory system for code intelligence
 * Explores different database approaches for agent memory
 */
/**
 * In-memory graph database for code relationships
 * Lightweight alternative to Neo4j for local use
 */
export class CodeGraphMemory {
    nodes = new Map();
    edges = new Map();
    temporalIndex = new Map(); // timestamp -> node IDs
    /**
     * Add a node to the graph
     */
    addNode(node) {
        this.nodes.set(node.id, node);
        // Add to temporal index
        const timestamp = node.timestamp.getTime();
        if (!this.temporalIndex.has(timestamp)) {
            this.temporalIndex.set(timestamp, []);
        }
        this.temporalIndex.get(timestamp).push(node.id);
    }
    /**
     * Add an edge between nodes
     */
    addEdge(edge) {
        if (!this.edges.has(edge.from)) {
            this.edges.set(edge.from, []);
        }
        this.edges.get(edge.from).push(edge);
    }
    /**
     * Find all nodes connected to a given node
     */
    getConnectedNodes(nodeId, edgeType, depth = 1) {
        const visited = new Set();
        const result = [];
        const traverse = (id, currentDepth) => {
            if (visited.has(id) || currentDepth > depth)
                return;
            visited.add(id);
            const node = this.nodes.get(id);
            if (node && currentDepth > 0) {
                result.push(node);
            }
            const edges = this.edges.get(id) || [];
            for (const edge of edges) {
                if (!edgeType || edge.type === edgeType) {
                    traverse(edge.to, currentDepth + 1);
                }
            }
        };
        traverse(nodeId, 0);
        return result;
    }
    /**
     * Find nodes modified within a time range
     */
    getNodesInTimeRange(start, end) {
        const startTime = start.getTime();
        const endTime = end.getTime();
        const result = [];
        for (const [timestamp, nodeIds] of this.temporalIndex) {
            if (timestamp >= startTime && timestamp <= endTime) {
                for (const nodeId of nodeIds) {
                    const node = this.nodes.get(nodeId);
                    if (node)
                        result.push(node);
                }
            }
        }
        return result;
    }
    /**
     * Find dependency chains
     */
    findDependencyChain(fromId, toId) {
        const paths = [];
        const visited = new Set();
        const dfs = (current, path) => {
            if (current === toId) {
                paths.push([...path]);
                return;
            }
            if (visited.has(current))
                return;
            visited.add(current);
            const edges = this.edges.get(current) || [];
            for (const edge of edges) {
                if (edge.type === 'depends_on' || edge.type === 'imports') {
                    const nextNode = this.nodes.get(edge.to);
                    if (nextNode) {
                        dfs(edge.to, [...path, nextNode]);
                    }
                }
            }
            visited.delete(current);
        };
        const startNode = this.nodes.get(fromId);
        if (startNode) {
            dfs(fromId, [startNode]);
        }
        return paths;
    }
    /**
     * Detect circular dependencies
     */
    detectCycles() {
        const cycles = [];
        const visited = new Set();
        const recursionStack = new Set();
        const dfs = (nodeId, path) => {
            visited.add(nodeId);
            recursionStack.add(nodeId);
            const edges = this.edges.get(nodeId) || [];
            for (const edge of edges) {
                if (!visited.has(edge.to)) {
                    dfs(edge.to, [...path, edge.to]);
                }
                else if (recursionStack.has(edge.to)) {
                    // Found a cycle
                    const cycleStart = path.indexOf(edge.to);
                    if (cycleStart !== -1) {
                        cycles.push(path.slice(cycleStart));
                    }
                }
            }
            recursionStack.delete(nodeId);
        };
        for (const nodeId of this.nodes.keys()) {
            if (!visited.has(nodeId)) {
                dfs(nodeId, [nodeId]);
            }
        }
        return cycles;
    }
}
/**
 * Document-based memory using embeddings and metadata
 */
export class DocumentMemory {
    documents = new Map();
    addDocument(id, content, metadata) {
        this.documents.set(id, {
            content,
            metadata,
            timestamp: new Date(),
        });
    }
    searchByMetadata(query) {
        const results = [];
        for (const [id, doc] of this.documents) {
            let matches = true;
            for (const [key, value] of Object.entries(query)) {
                if (doc.metadata[key] !== value) {
                    matches = false;
                    break;
                }
            }
            if (matches) {
                results.push([id, doc]);
            }
        }
        return results;
    }
}
/**
 * Time-series memory for tracking code evolution
 */
export class TimeSeriesMemory {
    events = [];
    addEvent(type, data, tags = []) {
        this.events.push({
            timestamp: new Date(),
            type,
            data,
            tags,
        });
    }
    queryByTimeRange(start, end, type) {
        return this.events.filter(event => {
            const inRange = event.timestamp >= start && event.timestamp <= end;
            const matchesType = !type || event.type === type;
            return inRange && matchesType;
        });
    }
    getEventPatterns(windowSize = 3600000) {
        const patterns = {};
        const now = Date.now();
        for (const event of this.events) {
            const age = now - event.timestamp.getTime();
            if (age <= windowSize) {
                patterns[event.type] = (patterns[event.type] || 0) + 1;
            }
        }
        return patterns;
    }
}
/**
 * Unified memory interface combining all approaches
 */
export class HybridCodeMemory {
    graph;
    documents;
    timeSeries;
    constructor() {
        this.graph = new CodeGraphMemory();
        this.documents = new DocumentMemory();
        this.timeSeries = new TimeSeriesMemory();
    }
    /**
     * Record a code change with full context
     */
    recordCodeChange(change) {
        // Add to graph
        const nodeId = `file:${change.file}:${Date.now()}`;
        this.graph.addNode({
            id: nodeId,
            type: 'file',
            name: change.file,
            properties: { changeType: change.type },
            timestamp: new Date(),
        });
        // Create relationships
        if (change.imports) {
            for (const imp of change.imports) {
                this.graph.addEdge({
                    from: nodeId,
                    to: `import:${imp}`,
                    type: 'imports',
                    timestamp: new Date(),
                });
            }
        }
        // Add to time series
        this.timeSeries.addEvent('code_change', change, [change.type, change.file]);
        // Add to documents
        this.documents.addDocument(nodeId, JSON.stringify(change), {
            file: change.file,
            type: change.type,
            timestamp: new Date(),
        });
    }
    /**
     * Query memory with context awareness
     */
    query(query) {
        switch (query.type) {
            case 'graph':
                // Use graph for relationship queries
                return this.graph.getConnectedNodes(query.query, undefined, query.depth);
            case 'temporal':
                // Use time series for time-based queries
                if (query.timeRange) {
                    return this.timeSeries.queryByTimeRange(query.timeRange.start, query.timeRange.end);
                }
                break;
            case 'semantic':
                // Use document store for content queries
                return this.documents.searchByMetadata({ type: query.query });
        }
    }
    /**
     * Get coding patterns and insights
     */
    getInsights() {
        return {
            recentPatterns: this.timeSeries.getEventPatterns(),
            dependencies: this.graph.detectCycles(),
            hotspots: this.findHotspots(),
        };
    }
    findHotspots() {
        const changeFrequency = {};
        const recentEvents = this.timeSeries.queryByTimeRange(new Date(Date.now() - 7 * 24 * 60 * 60 * 1000), // Last week
        new Date());
        for (const event of recentEvents) {
            if (event.data.file) {
                changeFrequency[event.data.file] = (changeFrequency[event.data.file] || 0) + 1;
            }
        }
        return Object.entries(changeFrequency)
            .sort((a, b) => b[1] - a[1])
            .slice(0, 10)
            .map(([file]) => file);
    }
}
//# sourceMappingURL=graph-memory.js.map