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.

162 lines 5.15 kB
/** * Portfolio Index Manager - Maps element names to file paths * * Solves critical issues: * 1. submit_collection_content can't find elements by metadata name (e.g., "Safe Roundtrip Tester" -> "safe-roundtrip-tester.md") * 2. search_collection doesn't search local portfolio content * * Features: * - In-memory index mapping metadata.name → file path * - Keywords/tags → file paths mapping * - Element type → file paths mapping * - Fast O(1) lookups with Maps * - Lazy loading with 5-minute TTL cache * - Unicode normalization for security * - Error handling and logging */ import { ElementType } from './types.js'; import { PortfolioManager } from './PortfolioManager.js'; import { IndexConfigManager } from './config/IndexConfig.js'; import { IFileOperationsService } from '../services/FileOperationsService.js'; export interface IndexEntry { filePath: string; elementType: ElementType; metadata: { name: string; description?: string; version?: string; author?: string; tags?: string[]; keywords?: string[]; triggers?: string[]; category?: string; created?: string; updated?: string; /** Agent V2 `activates` field — maps element types to element names. * Uses Record<string, string[]> intentionally (not AgentActivates) to * avoid coupling the index layer to agent-specific types and to support * future element types without index changes. */ activates?: Record<string, string[]>; }; lastModified: Date; filename: string; } export interface ShardedMemoryIndexEntry extends IndexEntry { shardInfo: { shardCount: number; shardDir: string; metadataFile: string; }; } export interface PortfolioIndex { byName: Map<string, IndexEntry>; byFilename: Map<string, IndexEntry>; byType: Map<ElementType, IndexEntry[]>; byKeyword: Map<string, IndexEntry[]>; byTag: Map<string, IndexEntry[]>; byTrigger: Map<string, IndexEntry[]>; } export interface SearchOptions { elementType?: ElementType; fuzzyMatch?: boolean; maxResults?: number; includeKeywords?: boolean; includeTags?: boolean; includeTriggers?: boolean; includeDescriptions?: boolean; } export interface SearchResult { entry: IndexEntry; matchType: 'name' | 'filename' | 'keyword' | 'tag' | 'trigger' | 'description'; score: number; } export declare class PortfolioIndexManager { private readonly indexConfigManager; private index; private lastBuilt; private readonly TTL_MS; private readonly portfolioManager; private readonly fileOperations; private isBuilding; private buildPromise; private readonly MAX_RETRIES; private readonly RETRY_DELAY_MS; constructor(indexConfigManager: IndexConfigManager, portfolioManager: PortfolioManager, fileOperations: IFileOperationsService); /** * Retry wrapper for file system operations * Handles transient file system errors with exponential backoff */ private retryFileOperation; /** * Get the current index, building it if necessary */ getIndex(): Promise<PortfolioIndex>; /** * Search the portfolio index by name with fuzzy matching */ findByName(name: string, options?: SearchOptions): Promise<IndexEntry | null>; /** * Search the portfolio with comprehensive text search */ search(query: string, options?: SearchOptions): Promise<SearchResult[]>; /** * Get all elements of a specific type */ getElementsByType(elementType: ElementType): Promise<IndexEntry[]>; /** * Get statistics about the index */ getStats(): Promise<{ totalElements: number; elementsByType: Record<ElementType, number>; lastBuilt: Date | null; isStale: boolean; }>; /** * Force rebuild the index */ rebuildIndex(): Promise<void>; /** * Check if the index needs rebuilding */ private needsRebuild; /** * Build the index by scanning all portfolio directories */ private buildIndex; /** * Perform the actual index building */ private performBuild; /** * Create an index entry from a file */ private createIndexEntry; /** * Create an index entry from a memory YAML file * FIX #1188: Special handling for memory files with different structure * FIX #1196: Use yaml.load for pure YAML files, not SecureYamlParser (which expects Markdown frontmatter) */ private createMemoryIndexEntry; /** * Add entry to all relevant index maps */ private addToIndex; /** * Find fuzzy matches for a name */ private findFuzzyMatch; /** * Calculate similarity between two strings */ private calculateSimilarity; /** * Check if any query tokens match the text */ private matchesQuery; /** * Dispose internal state to release resources (used during shutdown/tests). */ dispose(): void; } //# sourceMappingURL=PortfolioIndexManager.d.ts.map