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.

249 lines 8.69 kB
/** * MetadataService - Centralized metadata normalization and defaults * * Eliminates ~300 LOC of duplicate metadata handling across 6 element managers. * * Key Features: * - Consistent metadata structure across all element types * - Automatic default value assignment * - Version normalization (1.0 → 1.0.0) * - Unique ID generation * - User attribution with fallback chain * - Date formatting (ISO 8601) * * Architecture: * - Pure service (no state except currentUser) * - Type-safe with TypeScript strict mode * - Security-first (validates all inputs) * - Preserves exact current behavior from managers * * @example * ```typescript * const metadata = metadataService.normalizeMetadata( * { name: 'My Skill', description: 'Does things' }, * ElementType.SKILL * ); * // Returns: { name: 'My Skill', description: 'Does things', * // version: '1.0.0', author: 'user', created: '2025-11-19', ... } * ``` */ import { ElementType } from '../portfolio/types.js'; /** * Base metadata interface (common to all elements) */ export interface BaseMetadata { name: string; description: string; version?: string; author?: string; created?: string; modified?: string; tags?: string[]; triggers?: string[]; unique_id?: string; type?: ElementType; } /** * Options for metadata normalization */ export interface MetadataNormalizationOptions { /** Whether to preserve existing values instead of applying defaults (default: false) */ preserveExisting?: boolean; /** Whether to generate unique ID if missing (default: true) */ generateId?: boolean; /** Whether to normalize version format (default: true) */ normalizeVersion?: boolean; /** Whether to set current user as author (default: true) */ setAuthor?: boolean; /** Whether to set creation date if missing (default: true) */ setCreated?: boolean; /** Whether to set modified date (default: true) */ setModified?: boolean; /** Additional type-specific defaults to merge */ typeDefaults?: Record<string, any>; /** Skip applying typeDefaults (for BaseElement constructor) - only normalize common fields */ skipTypeDefaults?: boolean; } /** * MetadataService - Centralized metadata normalization and defaults * * ZERO FUNCTIONALITY LOSS: * This service extracts exact behavior from all 6 managers without any changes. * Every default value, every normalization rule, every edge case is preserved. * * USAGE: * ```typescript * const metadata = metadataService.normalizeMetadata( * rawMetadata, * ElementType.SKILL, * { * typeDefaults: { * category: 'general', * difficulty: 'intermediate' * } * } * ); * ``` */ export declare class MetadataService { private currentUser; /** * Normalize metadata with type-specific defaults * * Applies: * - Default values for missing fields * - Version normalization (1.0 → 1.0.0) * - Unique ID generation * - User attribution * - Date formatting (ISO 8601) * * PRESERVES EXACT BEHAVIOR: * - PersonaManager: lines 164-205 (normalizePersonaForSave) * - AgentManager: lines 113, 642-644 (getCurrentUserForAttribution) * - MemoryManager: lines 1342-1421 (parseMemoryFile metadata defaults) * - SkillManager: lines 44-102 (create method defaults) * - TemplateManager: lines 298-375 (validateMetadata defaults) * - EnsembleManager: lines 86-347 (parseMetadata defaults) * * @param raw - Raw metadata from user input or file * @param elementType - Type of element being created * @param options - Normalization options * @returns Fully normalized metadata * * @example * const metadata = metadataService.normalizeMetadata( * { name: 'My Skill', description: 'Does things' }, * ElementType.SKILL * ); * // Returns: { name: 'My Skill', description: 'Does things', * // version: '1.0.0', author: 'user', created: '2025-11-19', ... } */ normalizeMetadata<T extends BaseMetadata>(raw: Partial<T>, elementType: ElementType, options?: MetadataNormalizationOptions): T; /** * Generate default metadata for an element type * * Provides baseline metadata structure with all required fields populated. * Useful for creating new elements or testing. * * @param elementType - Type of element * @param overrides - Optional field overrides * @returns Default metadata structure * * @example * const defaults = metadataService.generateDefaultMetadata(ElementType.SKILL); * // Returns: { name: 'Untitled Skill', description: '', * // version: '1.0.0', author: 'anonymous', ... } */ generateDefaultMetadata(elementType: ElementType, overrides?: Partial<BaseMetadata>): BaseMetadata; /** * Assign a unique ID based on name and author * * Format: Uses existing generateUniqueId utility which creates: * `{slugified-name}-{author-hash}` or random UUID * * PRESERVES EXACT BEHAVIOR: * - PersonaManager line 181-182: generateUniqueId(metadata.name, metadata.author) * - PersonaManager line 567: generateUniqueId(sanitizedName, this.getCurrentUserForAttribution() || undefined) * * @param name - Element name * @param author - Element author * @returns Unique identifier string * * @example * const id = metadataService.assignUniqueId('My Skill', 'john'); * // Returns: 'my-skill-a3f8d9e2' (or similar hash) */ assignUniqueId(name: string, author: string): string; /** * Get current user for attribution * * Priority: * 1. Service-level currentUser (set via setCurrentUser) * 2. Environment variable DOLLHOUSE_USER * 3. OS system username (os.userInfo().username) * 4. Anonymous ID generation (last resort) * * The result is cached on first resolution so subsequent calls * return the same value without re-resolving. * * @returns Username or anonymous ID */ getCurrentUser(): string; /** * Set current user identity * * @param username - Username to set (null to clear) * * @example * metadataService.setCurrentUser('john'); * metadataService.setCurrentUser(null); // Clear */ setCurrentUser(username: string | null): void; /** * Normalize version string to semantic versioning format * * Handles: * - 1.0 → 1.0.0 * - 2 → 2.0.0 * - 1.2.3-beta → 1.2.3-beta (preserves pre-release) * * PRESERVES EXACT BEHAVIOR: * - PersonaManager line 173: metadata.version = normalizeVersion(metadata.version) * - PersonaManager line 786-787: normalizeVersion(String(editablePersona.version)) * - Uses existing normalizeVersion() utility from BaseElement * * @param version - Version string to normalize * @returns Normalized version string * * @example * const v = metadataService.normalizeVersion('1.0'); * // Returns: '1.0.0' */ normalizeVersion(version: string): string; /** * Generate ISO 8601 date string * * PRESERVES EXACT BEHAVIOR: * - PersonaManager line 178: new Date().toISOString().split('T')[0] (date-only) * - AgentManager line 231: new Date().toISOString() (full) * * @param format - Date format ('full' or 'date-only') * @returns Formatted date string * * @example * const date = metadataService.generateDate('date-only'); * // Returns: '2025-11-19' * * const datetime = metadataService.generateDate('full'); * // Returns: '2025-11-19T10:30:45.123Z' */ generateDate(format?: 'full' | 'date-only'): string; /** * Validate metadata completeness * * Checks: * - Required fields present (name, description) * - Valid types for all fields * - Value constraints (version format, etc.) * * @param metadata - Metadata to validate * @param elementType - Element type for type-specific validation * @returns Validation result * * @example * const result = metadataService.validateMetadata(metadata, ElementType.SKILL); * if (!result.valid) { * console.error('Validation errors:', result.errors); * } */ validateMetadata(metadata: BaseMetadata, elementType: ElementType): { valid: boolean; errors?: string[]; }; /** * Get human-readable element type name * @private */ private getElementTypeName; } //# sourceMappingURL=MetadataService.d.ts.map