@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.
221 lines • 9.05 kB
TypeScript
/**
* EnsembleManager - Implementation of IElementManager for Ensemble elements
*
* Handles CRUD operations and lifecycle management for ensembles implementing IElement
*
* ARCHITECTURE:
* - Extends BaseElementManager for unified element management
* - Follows template method pattern (parseMetadata, createElement hooks)
* - Pure manager layer - delegates business logic to Ensemble class
* - Uses DI for dependencies (PortfolioManager, FileLockManager)
*
* SECURITY:
* - Uses FileLockManager for atomic file operations
* - Path validation prevents directory traversal attacks
* - Input sanitization for all user data
* - Security event logging for audit trails
* - SecureYamlParser for safe YAML parsing
*/
import { Ensemble, EnsembleMetadata } from './Ensemble.js';
import { ElementValidationResult } from '../../types/elements/IElement.js';
import { BaseElementManager } from '../base/BaseElementManager.js';
import { FileLockManager } from '../../security/fileLockManager.js';
import { PortfolioManager } from '../../portfolio/PortfolioManager.js';
import { ValidationRegistry } from '../../services/validation/ValidationRegistry.js';
import { SerializationService } from '../../services/SerializationService.js';
import { MetadataService } from '../../services/MetadataService.js';
import { FileOperationsService } from '../../services/FileOperationsService.js';
import { FileWatchService } from '../../services/FileWatchService.js';
import { resolveElementTypes } from '../../utils/elementTypeResolver.js';
export { resolveElementTypes, type ElementManagersForResolution } from '../../utils/elementTypeResolver.js';
/** @deprecated Use resolveElementTypes from '../../utils/elementTypeResolver.js' */
export declare const resolveEnsembleElementTypes: typeof resolveElementTypes;
/**
* EnsembleManager - Manages ensemble element lifecycle
*
* Extends BaseElementManager to provide ensemble-specific operations:
* - YAML parsing with both snake_case and camelCase support
* - Ensemble creation and validation
* - Element reference management
* - Import/export in multiple formats
*/
export declare class EnsembleManager extends BaseElementManager<Ensemble> {
private metadataService;
private readonly ensemblesDir;
private validationService;
private serializationService;
private activeEnsembleNames;
private readonly legacyElementFieldWarnings;
constructor(portfolioManager: PortfolioManager, fileLockManager: FileLockManager, fileOperationsService: FileOperationsService, validationRegistry: ValidationRegistry, serializationService: SerializationService, metadataService: MetadataService, fileWatchService?: FileWatchService, memoryBudget?: import('../../cache/CacheMemoryBudget.js').CacheMemoryBudget, backupService?: import('../../services/BackupService.js').BackupService);
protected getElementLabel(): string;
/**
* Clear in-memory warn-once state for legacy ensemble element fields.
*
* Useful for long-lived processes or tests that intentionally want to
* observe the warning path again after a maintenance boundary.
*/
clearLegacyElementWarningHistory(): void;
dispose(): void;
/**
* Warn once per ensemble/index/field combination when a legacy nested field
* is encountered while loading or parsing an ensemble.
*
* Fingerprinting keeps the warning visible for each distinct legacy field
* without re-emitting the same deprecation notice on every re-parse.
*
* @param ensembleName - Name of the ensemble containing the legacy field
* @param index - Zero-based index of the element within the ensemble
* @param field - Legacy nested field name that should be migrated
*/
private warnOnceForLegacyElementField;
private hasLegacyElementFields;
/**
* Rewrite legacy ensemble element field names (`name`/`type`) to the
* canonical `element_name`/`element_type` form by loading and resaving
* affected ensembles.
*/
repairLegacyElementFields(): Promise<{
scanned: number;
repaired: number;
errors: number;
repairedEnsembles: Array<{
name: string;
path: string;
}>;
}>;
/**
* Parse metadata from YAML frontmatter
*
* NAMING CONVENTION SUPPORT:
* - TypeScript interfaces use camelCase (activationStrategy, conflictResolution)
* - YAML files can use snake_case (activation_strategy, conflict_resolution)
* - This method maps snake_case → camelCase for user convenience
*
* @param data - Raw YAML data from frontmatter
* @returns Validated EnsembleMetadata
*/
protected parseMetadata(data: any): Promise<EnsembleMetadata>;
/**
* Create an Ensemble instance from parsed metadata
*
* @param metadata - Validated ensemble metadata
* @param content - Markdown content (ensemble instructions/documentation)
* @returns New Ensemble instance
*/
protected createElement(metadata: EnsembleMetadata, _content: string): Ensemble;
/**
* Serialize an ensemble to file content
*
* Format: Markdown with YAML frontmatter
* - Frontmatter: Ensemble metadata + element references
* - Content: Instructions/documentation for the ensemble
*
* @param element - Ensemble to serialize
* @returns File content (markdown with frontmatter)
*/
protected serializeElement(element: Ensemble): Promise<string>;
private buildDefaultBody;
/**
* Get file extension for ensemble files
*/
getFileExtension(): string;
/**
* Import an ensemble from external format
*
* Supports:
* - YAML: Frontmatter-style metadata with optional markdown content
* - JSON: Direct ensemble structure
* - Markdown: YAML frontmatter + markdown content
*
* @param data - String containing ensemble data
* @param format - Format of the data (json, yaml, markdown)
* @returns Promise resolving to imported Ensemble
*/
importElement(data: string, format?: 'json' | 'yaml' | 'markdown'): Promise<Ensemble>;
/**
* Export an ensemble to external format
*
* @param element - Ensemble to export
* @param format - Output format (json, yaml, markdown)
* @returns Promise resolving to serialized string
*/
exportElement(element: Ensemble, format?: 'json' | 'yaml' | 'markdown'): Promise<string>;
/**
* Create a new ensemble with metadata
*
* @param metadata - Partial metadata for the ensemble
* @returns Promise resolving to new Ensemble instance
*/
create(metadata: Partial<EnsembleMetadata> & {
instructions?: string;
content?: string;
}): Promise<Ensemble>;
/**
* Validate an ensemble
* Delegates to ensemble's own validate method
*
* @param element - Ensemble to validate
* @returns Validation result
*/
validate(element: Ensemble): ElementValidationResult;
/**
* Override save to validate before persisting
*/
save(element: Ensemble, filePath: string): Promise<void>;
/**
* Override delete to add ensemble-specific logging
*/
delete(filePath: string): Promise<void>;
/**
* Override list to apply active status based on activeEnsembleNames set
*/
list(): Promise<Ensemble[]>;
/**
* Activate an ensemble by name or identifier
*
* Issue #24 (LOW PRIORITY): Performance optimization using findByName()
* Issue #24 (LOW PRIORITY): Consistent error messages using ElementMessages
* Issue #24 (LOW PRIORITY): Cleanup trigger for memory leak prevention
*
* @param identifier - Ensemble name or identifier
* @returns Activation result with success status and message
*/
activateEnsemble(identifier: string): Promise<{
success: boolean;
message: string;
ensemble?: Ensemble;
}>;
/**
* Deactivate an ensemble by name or identifier
*
* Issue #24 (LOW PRIORITY): Performance optimization using findByName()
* Issue #24 (LOW PRIORITY): Consistent error messages using ElementMessages
*
* @param identifier - Ensemble name or identifier
* @returns Deactivation result with success status and message
*/
deactivateEnsemble(identifier: string): Promise<{
success: boolean;
message: string;
ensemble?: Ensemble;
}>;
/**
* Get all active ensembles
*
* @returns List of active ensembles
*/
getActiveEnsembles(): Promise<Ensemble[]>;
/**
* Check if active set cleanup is needed and perform cleanup if necessary
* Issue #24 (LOW PRIORITY): Memory leak prevention
* @private
*/
private checkAndCleanupActiveSet;
/**
* Clean up stale entries from active ensembles set
* Issue #24 (LOW PRIORITY): Memory leak prevention
* @private
*/
private cleanupStaleActiveEnsembles;
}
//# sourceMappingURL=EnsembleManager.d.ts.map