UNPKG

@dollhousemcp/mcp-server

Version:

DollhouseMCP - A Model Context Protocol (MCP) server that enables dynamic AI persona management from markdown files, allowing Claude and other compatible AI assistants to activate and switch between different behavioral personas.

635 lines 19.7 kB
/** * Unified Index Manager - Combines local, GitHub, and collection portfolio indexing * * Features: * - Unified search across local, GitHub, and collection portfolios * - Intelligent result merging and deduplication * - Version conflict detection and resolution * - Performance optimization with parallel indexing * - Advanced fallback strategies for resilient operation * - Comprehensive search capabilities with pagination * - Smart result ranking and duplicate detection */ import { PortfolioIndexManager } from './PortfolioIndexManager.js'; import { GitHubPortfolioIndexer } from './GitHubPortfolioIndexer.js'; import { CollectionIndexCache } from '../cache/CollectionIndexCache.js'; import { GitHubClient } from '../collection/GitHubClient.js'; import { APICache } from '../cache/APICache.js'; import { ElementType } from './types.js'; import { FileOperationsService } from '../services/FileOperationsService.js'; import { LRUCache } from '../cache/LRUCache.js'; import { PerformanceMonitor } from '../utils/PerformanceMonitor.js'; import { ElementSource } from '../config/sourcePriority.js'; /** * Unified search options for searching across local, GitHub, and collection portfolios */ export interface UnifiedSearchOptions { /** Search query string */ query: string; /** * Include local portfolio in search (default: true) * * Local portfolio contains elements stored on the local filesystem in ~/.dollhouse/portfolio/. * This is typically the primary source for user's custom elements. */ includeLocal?: boolean; /** * Include GitHub portfolio in search (default: true) * * GitHub portfolio contains elements stored in the user's GitHub dollhouse-portfolio repository. * This provides backup and sync capabilities for elements. */ includeGitHub?: boolean; /** * Include collection in search (default: false) * * The collection contains community-contributed elements from the DollhouseMCP collection repository. * * **Why default is false:** * - Collection searches require network access and are slower than local/GitHub searches * - Most searches are for user's own elements, not community elements * - Reduces unnecessary network traffic and API rate limit usage * - Users can explicitly opt-in when browsing community content * * **When to use includeCollection: true:** * - Browsing or searching for community-contributed elements * - Looking for examples or templates from the collection * - Checking for updates to collection-sourced elements * - Using the browse/search collection features */ includeCollection?: boolean; /** Filter by specific element type */ elementType?: ElementType; /** Page number for pagination (default: 1) */ page?: number; /** Number of results per page (default: 20) */ pageSize?: number; /** Sort order for results (default: 'relevance') */ sortBy?: 'relevance' | 'source' | 'name' | 'version'; /** Enable result streaming for large result sets */ streamResults?: boolean; /** Pagination cursor for streaming results */ cursor?: string; /** Hard limit on total results returned */ maxResults?: number; /** Enable lazy loading of result details */ lazyLoad?: boolean; /** * Force search all enabled sources, ignoring stopOnFirst optimization (default: false) * * When true, searches all enabled sources even if earlier sources return results. * Useful for: * - Checking for duplicates across sources * - Finding all versions of an element * - Comprehensive searches where you need complete results */ includeAll?: boolean; /** * Prefer a specific source to search first * * Overrides the default priority order to search the specified source first. * Other sources are searched in default priority order after the preferred source. */ preferredSource?: ElementSource; /** * Custom source priority order * * Completely overrides the default source priority order. * Sources are searched in the order specified. */ sourcePriority?: ElementSource[]; } export interface VersionConflict { local?: string; github?: string; collection?: string; recommended: 'local' | 'github' | 'collection'; reason: string; } export interface DuplicateInfo { name: string; elementType: ElementType; sources: Array<{ source: 'local' | 'github' | 'collection'; version?: string; lastModified: Date; path?: string; }>; hasVersionConflict: boolean; versionConflict?: VersionConflict; } export interface VersionInfo { name: string; elementType: ElementType; versions: { local?: { version: string; lastModified: Date; path: string; }; github?: { version: string; lastModified: Date; path: string; }; collection?: { version: string; lastModified: Date; path: string; }; }; recommended: { source: 'local' | 'github' | 'collection'; reason: string; }; updateAvailable: boolean; updateFrom?: 'local' | 'github' | 'collection'; } export interface UnifiedIndexEntry { name: string; description?: string; version?: string; author?: string; elementType: ElementType; lastModified: Date; source: 'local' | 'github' | 'collection'; localFilePath?: string; filename?: string; tags?: string[]; keywords?: string[]; triggers?: string[]; category?: string; githubPath?: string; githubSha?: string; githubHtmlUrl?: string; githubDownloadUrl?: string; githubSize?: number; collectionPath?: string; collectionSha?: string; collectionTags?: string[]; collectionCategory?: string; collectionLicense?: string; } export interface UnifiedSearchResult { source: 'local' | 'github' | 'collection'; entry: UnifiedIndexEntry; matchType: string; score: number; version?: string; isDuplicate?: boolean; versionConflict?: VersionConflict; cursor?: string; } export interface StreamedSearchResult { results: UnifiedSearchResult[]; hasMore: boolean; nextCursor?: string; totalEstimate?: number; processingTimeMs: number; } export interface UnifiedIndexStats { local: { totalElements: number; elementsByType: Record<ElementType, number>; lastBuilt: Date | null; isStale: boolean; }; github: { totalElements: number; elementsByType: Record<ElementType, number>; lastFetched: Date | null; isStale: boolean; username?: string; repository?: string; }; collection: { totalElements: number; elementsByType: Record<string, number>; lastFetched: Date | null; isStale: boolean; version?: string; }; combined: { totalElements: number; uniqueElements: number; duplicates: number; }; performance: { averageSearchTime: number; cacheHitRate: number; lastOptimized: Date | null; }; } export interface UnifiedIndexManagerDependencies { portfolioIndexManager: PortfolioIndexManager; githubIndexer: GitHubPortfolioIndexer; collectionIndexCache: CollectionIndexCache; githubClient: GitHubClient; apiCache: APICache; rateLimitTracker: Map<string, number[]>; performanceMonitor: PerformanceMonitor; fileOperations: FileOperationsService; resultCache?: LRUCache<UnifiedSearchResult[]>; indexCache?: LRUCache<any>; } export declare class UnifiedIndexManager { private localIndexManager; private githubIndexer; private collectionIndexCache; private githubClient; private performanceMonitor; private resultCache; private indexCache; private readonly BATCH_SIZE; private readonly MAX_CONCURRENT_SOURCES; private ownsLocalIndexManager; private ownsGithubIndexer; private ownsCollectionIndexCache; private ownsPerformanceMonitor; private ownsResultCache; private ownsIndexCache; private readonly sourcePriorityConfig; private static readonly SOURCE_ENUM_TO_STRING_MAP; private static readonly SOURCE_STRING_TO_ENUM_MAP; private readonly sourceAvailabilityCache; private readonly sourceUsageTelemetry; constructor(dependencies: UnifiedIndexManagerDependencies); /** * Enhanced search across local, GitHub, and collection portfolios with performance optimization * * Implements source priority-based search (Issue #1446): * - Sources are searched sequentially in priority order (local → github → collection by default) * - Early termination when stopOnFirst is enabled and results are found * - Configurable priority order via sourcePriority or preferredSource options * - includeAll option forces search of all sources for comprehensive results */ search(searchOptions: UnifiedSearchOptions): Promise<UnifiedSearchResult[]>; /** * Normalize search options (extracted from search()) */ private normalizeSearchOptions; /** * Log security event for search operation (extracted from search()) */ private logSearchSecurityEvent; /** * Check search cache and return cached results if available (extracted from search()) */ private checkSearchCache; /** * Perform priority-based search across sources (extracted from search()) * * This is the core implementation of source priority search (Issue #1446): * - Searches sources sequentially in priority order * - Supports early termination with stopOnFirst * - Handles fallback on error * - Records telemetry for each source */ private performPriorityBasedSearch; /** * Search a single source and update results (extracted from performPriorityBasedSearch()) */ private searchSingleSource; /** * Check memory usage and trigger cleanup if needed (extracted from performPriorityBasedSearch()) */ private checkMemoryUsage; /** * Process final results: apply processing, pagination, caching, and metrics (extracted from search()) */ private processFinalResults; /** * Find element by name across all portfolios */ findByName(name: string, options?: Partial<UnifiedSearchOptions>): Promise<UnifiedIndexEntry | null>; /** * Get elements by type from all portfolios */ getElementsByType(elementType: ElementType, options?: Partial<UnifiedSearchOptions>): Promise<UnifiedIndexEntry[]>; /** * Check for duplicates across all sources */ checkDuplicates(name: string): Promise<DuplicateInfo[]>; /** * Get version comparison across all sources */ getVersionComparison(name: string): Promise<VersionInfo | null>; /** * Get comprehensive statistics across all sources */ getStats(): Promise<UnifiedIndexStats>; /** * Invalidate caches after user actions with performance monitoring */ invalidateAfterAction(action: string): void; /** * Force rebuild of all indexes with performance optimization */ rebuildAll(): Promise<void>; /** * Search with fallback strategies for resilient operation */ private searchWithFallback; /** * Handle search fallback strategies */ private handleSearchFallback; /** * Search local portfolio */ private searchLocal; /** * Search local with stale data fallback */ private searchLocalStale; /** * Search GitHub portfolio */ private searchGitHub; /** * Search GitHub with cached data fallback */ private searchGitHubCached; /** * Search collection portfolio */ private searchCollection; /** * Search collection with cached data fallback */ private searchCollectionCached; /** * Process search results with advanced features */ private processSearchResults; /** * Apply smart result ranking */ private applySmartRanking; /** * Detect duplicates and version conflicts */ private detectDuplicatesAndConflicts; /** * Apply pagination to results */ private applyPagination; /** * Apply sorting to results */ private applySorting; /** * Calculate match score for GitHub entries */ private calculateGitHubMatchScore; /** * Calculate match score for collection entries */ private calculateCollectionMatchScore; /** * Get all elements by type across sources */ private getAllElementsByType; /** * Get local elements by type */ private getLocalElementsByType; /** * Get GitHub elements by type */ private getGitHubElementsByType; /** * Get collection elements by type */ private getCollectionElementsByType; /** * Get local portfolio statistics */ private getLocalStats; /** * Get GitHub portfolio statistics */ private getGitHubStats; /** * Get collection portfolio statistics */ private getCollectionStats; /** * Calculate duplicates count across all sources * * Identifies elements that exist in multiple sources (local, GitHub, collection) */ private calculateDuplicatesCount; /** * Convert local index entry to unified format */ private convertLocalEntry; /** * Convert GitHub index entry to unified format */ private convertGitHubEntry; /** * Convert collection index entry to unified format */ private convertCollectionEntry; /** * Map string to ElementType enum */ private mapStringToElementType; /** * Convert unified search options to local search options */ private convertToLocalOptions; /** * Determine match type for GitHub entries */ private determineMatchType; /** * Determine match type for collection entries */ private determineCollectionMatchType; /** * Get path from unified entry */ private getPathFromEntry; /** * Detect version conflict from sources */ private detectVersionConflict; /** * Detect version conflict from search results */ private detectVersionConflictFromResults; /** * Determine version recommendation from version info */ private determineVersionRecommendation; /** * Determine version recommendation from sources */ private determineVersionRecommendationFromSources; /** * Compare semantic versions */ private compareVersions; /** * Remove duplicate results based on name and type */ private deduplicateResults; /** * Remove duplicate entries based on name and type */ private deduplicateEntries; /** * Stream search results for better performance with large datasets */ private streamSearch; /** * Process search results with memory-efficient batching */ private processSearchResultsOptimized; /** * Get enabled search sources */ private getEnabledSources; /** * Batch sources for concurrent processing */ private batchSources; /** * Generate cursor for pagination */ private generateCursor; /** * Trigger memory cleanup when usage is high */ private triggerMemoryCleanup; /** * Record search performance metrics */ private recordSearchMetrics; /** * Create cache key for search options */ private createCacheKey; /** * Initialize and validate source priority configuration * * Extracts configuration initialization into a separate method for testability * and adds validation to ensure configuration is valid. * * @returns Validated source priority configuration * @throws Error if configuration is invalid */ private initializeSourcePriorityConfig; /** * Validate source priority configuration * * @param config - Configuration to validate * @throws Error if configuration is invalid */ private validateSourcePriorityConfig; /** * Get enabled sources in priority order based on search options * * This method determines which sources to search and in what order based on: * 1. Custom sourcePriority override in options * 2. Preferred source override in options * 3. Default configuration priority order * * Then filters to only include sources that are enabled in the search options. * * @param options - Search options * @returns Array of enabled source names in priority order */ private getEnabledSourcesByPriority; /** * Determine source priority order from options (extracted from getEnabledSourcesByPriority) * * @param options - Search options * @returns Priority order as ElementSource array */ private determinePriorityOrder; /** * Filter sources to only those that are enabled (extracted from getEnabledSourcesByPriority) * * @param priorityOrder - Priority order to filter * @param options - Search options * @returns Filtered array of enabled source strings */ private filterEnabledSources; /** * Check if a source is enabled in search options * * Caches results for performance optimization. * * @param source - Source to check * @param options - Search options * @returns true if source is enabled */ private isSourceEnabled; /** * Clear the source availability cache * * Used for testing and when source availability changes */ private clearSourceAvailabilityCache; /** * Convert ElementSource enum to source string * * Uses optimized lookup table for O(1) performance. * * @param source - ElementSource enum value * @returns Source string ('local', 'github', or 'collection') * @throws Error if source is invalid */ private mapSourceEnumToString; /** * Convert source string to ElementSource enum * * Uses optimized lookup table for O(1) performance. * * @param source - Source string * @returns ElementSource enum value * @throws Error if source is invalid */ private mapSourceStringToEnum; /** * Record source usage telemetry * * Tracks search patterns for optimization insights. * * @param source - Source that was used * @param resultCount - Number of results returned * @param duration - Duration in milliseconds */ private recordSourceUsage; /** * Get source usage telemetry statistics * * @returns Map of source usage statistics */ getSourceUsageTelemetry(): Map<string, { searchCount: number; resultCount: number; totalDuration: number; lastUsed: Date; }>; /** * Reset source usage telemetry * * Used for testing and periodic cleanup */ resetSourceUsageTelemetry(): void; /** * Get performance statistics */ getPerformanceStats(): { searchStats: any; memoryStats: any; cacheStats: any; trends: any; }; dispose(): void; } //# sourceMappingURL=UnifiedIndexManager.d.ts.map