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.

250 lines 9.3 kB
/** * Type-safe relationship definitions for Enhanced Index * * This module provides a comprehensive type system for managing relationships * between elements in the DollhouseMCP Enhanced Index. It implements a three-tier * type hierarchy that ensures both compile-time and runtime safety. * * ## Type Hierarchy: * 1. BaseRelationship - The storage format (what's persisted to disk) * 2. ParsedRelationship - Valid runtime format with extracted metadata * 3. InvalidRelationship - Error state with detailed diagnostics * * ## Key Features: * - Strongly-typed interfaces with discriminated unions * - Runtime type guards for safe type narrowing * - Detailed error messages with position information * - Batch processing utilities with performance optimizations * - Relationship deduplication and sorting algorithms * * ## Usage Example: * ```typescript * // Parse a relationship from storage * const stored: BaseRelationship = { element: 'personas:expert-coder' }; * const parsed = parseRelationship(stored); * * if (isParsedRelationship(parsed)) { * console.log(`Type: ${parsed.targetType}, Name: ${parsed.targetName}`); * } else { * console.error(`Parse failed: ${parsed.parseError}`); * } * ``` * * FIXES IMPLEMENTED (Issue #1103): * - Type-safe relationship variants with discriminated unions * - Compile-time validation through TypeScript's type system * - Runtime type guards for safe type narrowing * - Safe parsing utilities with detailed error reporting * - Security audit logging for relationship operations */ /** * Base relationship interface - the storage format * * This is the fundamental relationship structure that gets persisted to disk. * It contains only the raw data without any parsed or computed fields. * * @example * ```typescript * const relationship: BaseRelationship = { * element: 'skills:debugging', * type: 'similar_to', * strength: 0.85, * metadata: { reason: 'Both involve code analysis' } * }; * ``` */ export interface BaseRelationship { /** Element ID in format "type:name" (e.g., "personas:expert", "skills:refactor") */ element: string; /** Semantic relationship type from RelationshipTypes enum (e.g., 'uses', 'similar_to', 'extends') */ type?: string; /** Relationship strength/confidence score between 0.0 and 1.0 (inclusive) */ strength?: number; /** Extensible metadata for custom properties (e.g., similarity scores, timestamps) */ metadata?: Record<string, any>; } /** * Parsed relationship with extracted type and name components * * This is the runtime format after successfully parsing a BaseRelationship. * It includes all base fields plus extracted metadata for efficient querying. * * @example * ```typescript * const parsed: ParsedRelationship = { * element: 'personas:expert-coder', * type: 'similar_to', * strength: 0.9, * targetType: 'personas', // Extracted from element * targetName: 'expert-coder', // Extracted from element * isValid: true // Type discriminator * }; * ``` */ export interface ParsedRelationship extends BaseRelationship { /** Extracted element type (e.g., 'personas', 'skills', 'templates') */ targetType: string; /** Extracted element name (e.g., 'expert-coder', 'debugging') */ targetName: string; /** Type discriminator - always true for valid parsed relationships */ isValid: true; } /** * Invalid relationship state with diagnostic information * * This type represents a relationship that failed to parse, preserving * the original data while providing detailed error context for debugging. * * @example * ```typescript * const invalid: InvalidRelationship = { * element: 'malformed:element:id', * targetType: null, * targetName: null, * isValid: false, * parseError: 'Invalid element ID format: "malformed:element:id" - multiple separators...' * }; * ``` */ export interface InvalidRelationship extends BaseRelationship { /** Null when parsing fails */ targetType: null; /** Null when parsing fails */ targetName: null; /** Type discriminator - always false for invalid relationships */ isValid: false; /** Detailed error message with position information and expected format */ parseError: string; } /** * Union type for all relationship variants */ export type Relationship = BaseRelationship | ParsedRelationship | InvalidRelationship; /** * Type guard to check if a relationship is successfully parsed * * @param rel - The relationship to check * @returns True if the relationship is a ParsedRelationship with valid data * * @example * ```typescript * const rel = parseRelationship(baseRel); * if (isParsedRelationship(rel)) { * // TypeScript knows rel is ParsedRelationship here * console.log(rel.targetType, rel.targetName); * } * ``` */ export declare function isParsedRelationship(rel: Relationship): rel is ParsedRelationship; /** * Type guard to check if a relationship failed to parse * * @param rel - The relationship to check * @returns True if the relationship is an InvalidRelationship with error details * * @example * ```typescript * const rel = parseRelationship(baseRel); * if (isInvalidRelationship(rel)) { * console.error(`Parse failed: ${rel.parseError}`); * } * ``` */ export declare function isInvalidRelationship(rel: Relationship): rel is InvalidRelationship; /** * Type guard to check if a relationship is unparsed (base type only) * * @param rel - The relationship to check * @returns True if the relationship is a BaseRelationship without parsed fields * * @example * ```typescript * if (isBaseRelationship(rel)) { * // Need to parse this relationship before use * const parsed = parseRelationship(rel); * } * ``` */ export declare function isBaseRelationship(rel: Relationship): rel is BaseRelationship; /** * Safely parse a base relationship into a typed relationship variant * * This function attempts to parse the element ID and extract type/name components. * If parsing fails, it returns an InvalidRelationship with detailed error context * including position information and what was expected. * * @param rel - The base relationship to parse * @returns ParsedRelationship if successful, InvalidRelationship with diagnostics if failed * * @example Success case * ```typescript * const base: BaseRelationship = { element: 'skills:debugging' }; * const result = parseRelationship(base); * // result: ParsedRelationship with targetType='skills', targetName='debugging' * ``` * * @example Error cases with detailed diagnostics * ```typescript * parseRelationship({ element: 'no-separator' }); * // Error: "missing separator ':'" * * parseRelationship({ element: ':missing-type' }); * // Error: "missing type before ':'" * * parseRelationship({ element: 'too:many:colons' }); * // Error: "multiple separators ':' found at positions [3, 8]" * ``` */ export declare function parseRelationship(rel: BaseRelationship): ParsedRelationship | InvalidRelationship; /** * Batch parse relationships with type safety * Filters out invalid relationships by default */ export declare function parseRelationships(relationships: BaseRelationship[], includeInvalid?: boolean): ParsedRelationship[] | (ParsedRelationship | InvalidRelationship)[]; /** * Create a new relationship with validation */ export declare function createRelationship(targetType: string, targetName: string, relationType?: string, strength?: number, metadata?: Record<string, any>): ParsedRelationship; /** * Validate a relationship has required fields */ export declare function validateRelationship(rel: any): rel is BaseRelationship; /** * Group relationships by target type for efficient processing */ export declare function groupRelationshipsByType(relationships: ParsedRelationship[]): Map<string, ParsedRelationship[]>; /** * Find duplicate relationships (same target element) */ export declare function findDuplicateRelationships(relationships: BaseRelationship[]): BaseRelationship[][]; /** * Merge duplicate relationships, keeping highest strength */ export declare function deduplicateRelationships(relationships: BaseRelationship[]): BaseRelationship[]; /** * Sort relationships by strength (descending) */ export declare function sortRelationshipsByStrength(relationships: BaseRelationship[]): BaseRelationship[]; /** * Filter relationships by minimum strength threshold */ export declare function filterRelationshipsByStrength(relationships: BaseRelationship[], minStrength: number): BaseRelationship[]; /** * Relationship type aliases for common patterns */ export declare const RelationshipTypes: { readonly SIMILAR_TO: "similar_to"; readonly USES: "uses"; readonly USED_BY: "used_by"; readonly EXTENDS: "extends"; readonly EXTENDED_BY: "extended_by"; readonly CONTAINS: "contains"; readonly CONTAINED_BY: "contained_by"; readonly HELPS_DEBUG: "helps_debug"; readonly DEBUGGED_BY: "debugged_by"; readonly CONTRADICTS: "contradicts"; readonly SUPPORTS: "supports"; readonly SEMANTIC_SIMILARITY: "semantic_similarity"; }; export type RelationshipType = typeof RelationshipTypes[keyof typeof RelationshipTypes]; //# sourceMappingURL=RelationshipTypes.d.ts.map