UNPKG

meld

Version:

Meld: A template language for LLM prompts

1,493 lines (1,464 loc) 80.1 kB
import { MeldNode, DirectiveNode } from 'meld-spec'; import * as fsExtra from 'fs-extra'; import { Stats } from 'fs-extra'; import { Stats as Stats$1 } from 'fs'; import * as path from 'path'; /** * @package * Core event system for state tracking. * * @remarks * Provides event emission and handling for state operations. */ /** * Core state event types as defined in the instrumentation plan */ type StateEventType = 'create' | 'clone' | 'transform' | 'merge' | 'error'; /** * Base state event interface */ interface StateEvent { type: StateEventType; stateId: string; source: string; timestamp: number; location?: { file?: string; line?: number; column?: number; }; } /** * Event handler function type */ type StateEventHandler = (event: StateEvent) => void | Promise<void>; /** * Event filter predicate */ type StateEventFilter = (event: StateEvent) => boolean; /** * Handler registration options */ interface StateEventHandlerOptions { filter?: StateEventFilter; } /** * Core state event service interface */ interface IStateEventService { /** * Register an event handler with optional filtering */ on(type: StateEventType, handler: StateEventHandler, options?: StateEventHandlerOptions): void; /** * Remove an event handler */ off(type: StateEventType, handler: StateEventHandler): void; /** * Emit a state event */ emit(event: StateEvent): Promise<void>; /** * Get all registered handlers for an event type */ getHandlers(type: StateEventType): Array<{ handler: StateEventHandler; options?: StateEventHandlerOptions; }>; } /** * @package * Interface for state tracking service. */ interface IStateTrackingService { /** * Register a state with the tracking service. * @param metadata - The state metadata to register */ registerState(metadata: Partial<StateMetadata>): void; /** * Add a relationship between two states. * @param sourceId - The source state ID * @param targetId - The target state ID * @param type - The type of relationship */ addRelationship(sourceId: string, targetId: string, type: 'parent-child' | 'merge-source' | 'merge-target'): void; /** * Get the complete lineage of a state from root to the given state. * @param stateId - The ID of the state to get lineage for * @param visited - Set of visited states to prevent cycles * @returns Array of state IDs representing the lineage from root to target state */ getStateLineage(stateId: string, visited?: Set<string>): string[]; /** * Get all descendants of a state. * @param stateId - The ID of the state to get descendants for * @param visited - Set of visited states to prevent cycles * @returns Array of state IDs representing all descendants */ getStateDescendants(stateId: string, visited?: Set<string>): string[]; /** * Get all registered states. * @returns Array of state metadata for all registered states */ getAllStates(): StateMetadata[]; /** * Get metadata for a specific state. * @param stateId - The ID of the state to get metadata for * @returns The state metadata or undefined if not found */ getStateMetadata(stateId: string): StateMetadata | undefined; /** * Track a context boundary between two states. * @param sourceStateId - The source state ID * @param targetStateId - The target state ID * @param boundaryType - The type of boundary * @param filePath - Optional file path associated with the boundary */ trackContextBoundary(sourceStateId: string, targetStateId: string, boundaryType: 'import' | 'embed', filePath?: string): void; /** * Track a variable crossing between two states. * @param sourceStateId - The source state ID * @param targetStateId - The target state ID * @param variableName - The name of the variable * @param variableType - The type of variable * @param alias - Optional alias for the variable in the target state */ trackVariableCrossing(sourceStateId: string, targetStateId: string, variableName: string, variableType: 'text' | 'data' | 'path' | 'command', alias?: string): void; /** * Get all context boundaries. * @returns Array of context boundaries */ getContextBoundaries(): ContextBoundary[]; /** * Get variable crossings for a state. * @param stateId - The ID of the state to get variable crossings for * @returns Array of variable crossings */ getVariableCrossings(stateId: string): VariableCrossing[]; /** * Get the context hierarchy for a state. * @param rootStateId - The ID of the root state * @returns Context hierarchy information */ getContextHierarchy(rootStateId: string): ContextHierarchyInfo; } /** * Metadata for a state instance. */ interface StateMetadata { id: string; parentId?: string; source: 'new' | 'clone' | 'child' | 'merge' | 'implicit'; filePath?: string; transformationEnabled: boolean; createdAt: number; lastModified?: number; childStates?: string[]; } /** * Represents a relationship between states. */ interface StateRelationship { sourceId?: string; targetId: string; type: 'parent-child' | 'merge-source' | 'merge-target'; } /** * Represents a context boundary between states. */ interface ContextBoundary { sourceStateId: string; targetStateId: string; boundaryType: 'import' | 'embed'; timestamp: number; filePath?: string; } /** * Represents a variable crossing between states. */ interface VariableCrossing { sourceStateId: string; targetStateId: string; variableName: string; variableType: 'text' | 'data' | 'path' | 'command'; timestamp: number; alias?: string; } /** * Information about the context hierarchy. */ interface ContextHierarchyInfo { states: StateMetadata[]; boundaries: ContextBoundary[]; variableCrossings: VariableCrossing[]; } /** * Options for selective transformation */ interface TransformationOptions { variables?: boolean; directives?: boolean; commands?: boolean; imports?: boolean; } interface IStateService { setEventService(eventService: IStateEventService): void; setTrackingService(trackingService: IStateTrackingService): void; getStateId(): string | undefined; getTextVar(name: string): string | undefined; setTextVar(name: string, value: string): void; getAllTextVars(): Map<string, string>; getLocalTextVars(): Map<string, string>; getDataVar(name: string): unknown; setDataVar(name: string, value: unknown): void; getAllDataVars(): Map<string, unknown>; getLocalDataVars(): Map<string, unknown>; getPathVar(name: string): string | undefined; setPathVar(name: string, value: string): void; getAllPathVars(): Map<string, string>; getCommand(name: string): { command: string; options?: Record<string, unknown>; } | undefined; setCommand(name: string, command: string | { command: string; options?: Record<string, unknown>; }): void; getAllCommands(): Map<string, { command: string; options?: Record<string, unknown>; }>; getNodes(): MeldNode[]; addNode(node: MeldNode): void; appendContent(content: string): void; getTransformedNodes(): MeldNode[]; setTransformedNodes(nodes: MeldNode[]): void; transformNode(original: MeldNode, transformed: MeldNode): void; isTransformationEnabled(): boolean; enableTransformation(options?: TransformationOptions | boolean): void; shouldTransform(type: keyof TransformationOptions): boolean; getTransformationOptions(): TransformationOptions; getCommandOutput(command: string): string | undefined; hasTransformationSupport(): boolean; addImport(path: string): void; removeImport(path: string): void; hasImport(path: string): boolean; getImports(): Set<string>; getCurrentFilePath(): string | null; setCurrentFilePath(path: string): void; hasLocalChanges(): boolean; getLocalChanges(): string[]; setImmutable(): void; readonly isImmutable: boolean; createChildState(): IStateService; mergeChildState(childState: IStateService): void; clone(): IStateService; } interface IValidationService { /** * Validate a directive node against its schema and constraints * @throws {MeldDirectiveError} If validation fails */ validate(node: DirectiveNode): Promise<void>; /** * Register a validator function for a specific directive kind */ registerValidator(kind: string, validator: (node: DirectiveNode) => Promise<void>): void; /** * Remove a validator for a specific directive kind */ removeValidator(kind: string): void; /** * Check if a validator exists for a specific directive kind */ hasValidator(kind: string): boolean; /** * Get all registered directive kinds that can be validated */ getRegisteredDirectiveKinds(): string[]; } interface IFileSystem { readFile(path: string): Promise<string>; writeFile(path: string, content: string): Promise<void>; exists(path: string): Promise<boolean>; stat(path: string): Promise<Stats>; readDir(path: string): Promise<string[]>; mkdir(path: string): Promise<void>; isDirectory(path: string): Promise<boolean>; isFile(path: string): Promise<boolean>; watch(path: string, options?: { recursive?: boolean; }): AsyncIterableIterator<{ filename: string; eventType: string; }>; executeCommand(command: string, options?: { cwd?: string; }): Promise<{ stdout: string; stderr: string; }>; isTestEnvironment?: boolean; } interface IFileSystemService { readFile(filePath: string): Promise<string>; writeFile(filePath: string, content: string): Promise<void>; exists(filePath: string): Promise<boolean>; stat(filePath: string): Promise<Stats>; isFile(filePath: string): Promise<boolean>; readDir(dirPath: string): Promise<string[]>; ensureDir(dirPath: string): Promise<void>; isDirectory(filePath: string): Promise<boolean>; watch(path: string, options?: { recursive?: boolean; }): AsyncIterableIterator<{ filename: string; eventType: string; }>; getCwd(): string; dirname(filePath: string): string; executeCommand(command: string, options?: { cwd?: string; }): Promise<{ stdout: string; stderr: string; }>; setFileSystem(fileSystem: IFileSystem): void; getFileSystem(): IFileSystem; } /** * Adapter to use Node's fs-extra as our IFileSystem implementation */ declare class NodeFileSystem implements IFileSystem { isTestEnvironment: boolean; readFile(path: string): Promise<string>; writeFile(path: string, content: string): Promise<void>; exists(path: string): Promise<boolean>; stat(path: string): Promise<Stats$1>; readDir(path: string): Promise<string[]>; mkdir(path: string): Promise<void>; isDirectory(path: string): Promise<boolean>; isFile(path: string): Promise<boolean>; watch(path: string, options?: { recursive?: boolean; }): AsyncIterableIterator<{ filename: string; eventType: string; }>; executeCommand(command: string, options?: { cwd?: string; }): Promise<{ stdout: string; stderr: string; }>; } type OutputFormat = 'markdown' | 'xml'; interface OutputOptions { /** * Whether to include state variables in the output * @default false */ includeState?: boolean; /** * Whether to preserve original formatting (whitespace, newlines) * @default true */ preserveFormatting?: boolean; /** * Custom format-specific options */ formatOptions?: Record<string, unknown>; } interface IOutputService { /** * Check if this service can access transformed nodes * @returns true if transformed nodes can be accessed */ canAccessTransformedNodes(): boolean; /** * Convert Meld nodes and state to the specified output format. * If state.isTransformationEnabled() is true and state.getTransformedNodes() is available, * the transformed nodes will be used instead of the input nodes. * * In non-transformation mode: * - Definition directives (@text, @data, @path, @import, @define) are omitted * - Execution directives (@run, @embed) show placeholders * * In transformation mode: * - All directives are replaced with their transformed results * - Plain text and code fences are preserved as-is * * @throws {MeldOutputError} If conversion fails */ convert(nodes: MeldNode[], state: IStateService, format: OutputFormat, options?: OutputOptions): Promise<string>; /** * Register a custom format converter */ registerFormat(format: string, converter: (nodes: MeldNode[], state: IStateService, options?: OutputOptions) => Promise<string>): void; /** * Check if a format is supported */ supportsFormat(format: string): boolean; /** * Get a list of all supported formats */ getSupportedFormats(): string[]; } interface IParserService { /** * Parse Meld content into an AST using meld-ast. * @param content The Meld content to parse * @returns A promise that resolves to an array of MeldNodes representing the AST * @throws {MeldParseError} If the content cannot be parsed */ parse(content: string): Promise<MeldNode[]>; /** * Parse Meld content and provide location information for each node. * This is useful for error reporting and source mapping. * @param content The Meld content to parse * @param filePath Optional file path for better error messages * @returns A promise that resolves to an array of MeldNodes with location information * @throws {MeldParseError} If the content cannot be parsed */ parseWithLocations(content: string, filePath?: string): Promise<MeldNode[]>; } /** * @package * Lightweight tracking for variable resolution attempts * * Provides tracking capability to monitor variable resolution attempts * with minimal performance impact when disabled */ /** * Resolution attempt information */ interface ResolutionAttempt { variableName: string; context: string; timestamp: number; success: boolean; value?: any; source?: string; contextBoundary?: { type: 'parent-to-child' | 'child-to-parent'; sourceId?: string; targetId?: string; }; } /** * Variable resolution tracking configuration */ interface ResolutionTrackingConfig { enabled: boolean; samplingRate?: number; maxAttempts?: number; watchVariables?: string[]; } /** * Tracks variable resolution attempts with minimal performance impact when disabled */ declare class VariableResolutionTracker { private config; private attempts; /** * Enables or disables tracking */ configure(config: Partial<ResolutionTrackingConfig>): void; /** * Track a variable resolution attempt with minimal overhead when disabled */ trackResolutionAttempt(variableName: string, context: string, success: boolean, value?: any, source?: string, contextBoundary?: { type: 'parent-to-child' | 'child-to-parent'; sourceId?: string; targetId?: string; }): void; /** * Get all tracked resolution attempts */ getAttempts(): ResolutionAttempt[]; /** * Get resolution attempts for a specific variable */ getAttemptsForVariable(variableName: string): ResolutionAttempt[]; /** * Clear all tracked attempts */ clearAttempts(): void; /** * Check if tracking is enabled */ isEnabled(): boolean; } /** * Interface matching the StructuredPath expected from meld-spec */ interface StructuredPath$2 { raw: string; structured: { segments: string[]; variables?: { special?: string[]; path?: string[]; }; cwd?: boolean; }; normalized?: string; isVariableReference?: boolean; } /** * Context for variable resolution, specifying what types of variables and operations are allowed */ interface ResolutionContext { /** Current file being processed, for error reporting */ currentFilePath?: string; /** What types of variables are allowed in this context */ allowedVariableTypes: { text: boolean; data: boolean; path: boolean; command: boolean; }; /** Path validation rules when resolving paths */ pathValidation?: { requireAbsolute: boolean; allowedRoots: string[]; }; /** Whether field access is allowed for data variables */ allowDataFields?: boolean; /** Whether to throw errors on resolution failures (true) or attempt to recover (false) */ strict?: boolean; /** The state service to use for variable resolution */ state: IStateService; } /** * Service responsible for resolving variables, commands, and paths in different contexts */ interface IResolutionService { /** * Resolve text variables ({{var}}) in a string * Formerly used ${var} syntax, now unified with data variables to use {{var}} */ resolveText(text: string, context: ResolutionContext): Promise<string>; /** * Resolve data variables and fields (#{data.field}) to their values */ resolveData(ref: string, context: ResolutionContext): Promise<any>; /** * Resolve path variables ($path) to absolute paths. * This includes $HOMEPATH/$~ and $PROJECTPATH/$. resolution. */ resolvePath(path: string, context: ResolutionContext): Promise<string>; /** * Resolve command references ($command(args)) to their results */ resolveCommand(cmd: string, args: string[], context: ResolutionContext): Promise<string>; /** * Resolve content from a file path */ resolveFile(path: string): Promise<string>; /** * Resolve raw content nodes, preserving formatting but skipping comments */ resolveContent(nodes: MeldNode[], context: ResolutionContext): Promise<string>; /** * Resolve any value based on the provided context rules */ resolveInContext(value: string | StructuredPath$2, context: ResolutionContext): Promise<string>; /** * Validate that resolution is allowed in the given context */ validateResolution(value: string | StructuredPath$2, context: ResolutionContext): Promise<void>; /** * Extract a section from content by its heading * @param content The content to extract the section from * @param section The heading text to search for * @param fuzzy Optional fuzzy matching threshold (0-1, where 1 is exact match, defaults to 0.7) */ extractSection(content: string, section: string, fuzzy?: number): Promise<string>; /** * Check for circular variable references */ detectCircularReferences(value: string): Promise<void>; /** * Enable tracking of variable resolution attempts * @param config Configuration for the resolution tracker */ enableResolutionTracking(config: Partial<ResolutionTrackingConfig>): void; /** * Get the resolution tracker for debugging * @returns The current resolution tracker or undefined if not enabled */ getResolutionTracker(): VariableResolutionTracker | undefined; } declare class ParserService implements IParserService { private resolutionService?; constructor(resolutionService?: IResolutionService); setResolutionService(resolutionService: IResolutionService): void; private parseContent; parse(content: string, filePath?: string): Promise<MeldNode[]>; parseWithLocations(content: string, filePath?: string): Promise<MeldNode[]>; private isParseError; private validateCodeFences; /** * Transform a variable node to its resolved value * Used for preview and transformation mode to resolve values * @param node The node to transform * @param state The state service to use for lookup * @returns A text node with the resolved value if transformation is enabled */ transformVariableNode(node: MeldNode, state: IStateService): Promise<MeldNode>; } /** * Command definition with optional configuration */ interface CommandDefinition { readonly command: string; readonly options?: Readonly<Record<string, unknown>>; } declare class StateService implements IStateService { private stateFactory; private currentState; private _isImmutable; private _transformationEnabled; private _transformationOptions; private eventService?; private trackingService?; constructor(parentState?: IStateService); setEventService(eventService: IStateEventService): void; private emitEvent; getTextVar(name: string): string | undefined; setTextVar(name: string, value: string): void; getAllTextVars(): Map<string, string>; getLocalTextVars(): Map<string, string>; getDataVar(name: string): unknown; setDataVar(name: string, value: unknown): void; getAllDataVars(): Map<string, unknown>; getLocalDataVars(): Map<string, unknown>; getPathVar(name: string): string | undefined; setPathVar(name: string, value: string): void; getAllPathVars(): Map<string, string>; getCommand(name: string): CommandDefinition | undefined; setCommand(name: string, command: string | CommandDefinition): void; getAllCommands(): Map<string, CommandDefinition>; getNodes(): MeldNode[]; getTransformedNodes(): MeldNode[]; setTransformedNodes(nodes: MeldNode[]): void; addNode(node: MeldNode): void; transformNode(original: MeldNode, transformed: MeldNode): void; isTransformationEnabled(): boolean; /** * Check if a specific transformation type is enabled * @param type The transformation type to check (variables, directives, commands, imports) * @returns Whether the specified transformation type is enabled */ shouldTransform(type: keyof TransformationOptions): boolean; /** * Enable transformation with specific options * @param options Options for selective transformation, or true/false for all */ enableTransformation(options?: TransformationOptions | boolean): void; /** * Get the current transformation options * @returns The current transformation options */ getTransformationOptions(): TransformationOptions; appendContent(content: string): void; addImport(path: string): void; removeImport(path: string): void; hasImport(path: string): boolean; getImports(): Set<string>; getCurrentFilePath(): string | null; setCurrentFilePath(path: string): void; /** * In the immutable state model, any non-empty state is considered to have local changes. * This is a deliberate design choice - each state represents a complete snapshot, * so the entire state is considered "changed" from its creation. * * @returns Always returns true to indicate the state has changes */ hasLocalChanges(): boolean; /** * Returns a list of changed elements in the state. In the immutable state model, * the entire state is considered changed from creation, so this always returns * ['state'] to indicate the complete state has changed. * * This is a deliberate design choice that aligns with the immutable state model * where each state is a complete snapshot. * * @returns Always returns ['state'] to indicate the entire state has changed */ getLocalChanges(): string[]; setImmutable(): void; get isImmutable(): boolean; createChildState(): IStateService; mergeChildState(childState: IStateService): void; clone(): IStateService; private checkMutable; /** * Deep clones a value, handling objects, arrays, Maps, Sets, and circular references. * @param value The value to clone * @param seen A WeakMap to track circular references * @returns A deep clone of the value */ private deepCloneValue; private updateState; setTrackingService(trackingService: IStateTrackingService): void; getStateId(): string | undefined; getCommandOutput(command: string): string | undefined; hasTransformationSupport(): boolean; } /** * Handles resolution of variable references ({{var}}) * Previously used ${var} for text and #{var} for data, now unified as {{var}} */ declare class VariableReferenceResolver { private readonly stateService; private readonly resolutionService?; private readonly parserService?; private readonly MAX_RESOLUTION_DEPTH; private readonly MAX_ITERATIONS; private resolutionTracker?; constructor(stateService: IStateService, resolutionService?: IResolutionService | undefined, parserService?: IParserService | undefined); /** * Set the resolution tracker for debugging * @internal */ setResolutionTracker(tracker: VariableResolutionTracker): void; /** * Resolves all variable references in the given text * @param text Text containing variable references like {{varName}} * @param context Resolution context * @returns Resolved text with all variables replaced with their values */ resolve(content: string, context: ResolutionContext): Promise<string>; /** * Resolves a list of nodes, handling variable references * @param nodes The nodes to resolve * @param context The resolution context * @returns The resolved content */ resolveNodes(nodes: MeldNode[], context: ResolutionContext): Promise<string>; /** * Extract the actual value from a node, not just its string representation */ private getNodeValue; /** * Convert a node to string representation * @deprecated Use getNodeValue instead for actual variable values */ private nodeToString; /** * Resolve text with variable references */ private resolveText; /** * Resolves a variable node (TextVar or DataVar) * @param node The variable node to resolve * @param context The resolution context * @param resolutionPath Path to detect circular references * @returns The resolved value */ private resolveVarNode; /** * Normalizes a variable node to a common format regardless of node type */ private normalizeVarNode; /** * Handles the resolution of standard text variables using a simpler approach * @param text Text containing variable references * @param context Resolution context * @returns Text with variables resolved */ private resolveSimpleVariables; /** * Extract variable nodes from the AST * @param nodes AST nodes * @returns Array of variable reference nodes */ private extractVariableNodesFromAst; /** * Extract references using AST - now properly handles async */ private extractReferencesAst; /** * Extract references from AST nodes */ private extractReferencesFromNodes; /** * Extract references from text content (helper method) */ private extractReferencesFromText; /** * Extract references using regex pattern matching - now delegates to async method * This is kept for backward compatibility */ private extractReferencesRegex; private getSafeTextVars; private getSafeDataVars; private resolveWithAst; /** * Check if text contains variable references */ private hasVariableReferences; /** * Extract variable references from a string - now properly uses parser when available * @param text The text to search for references * @returns Array of unique variable names */ extractReferences(text: string): string[]; /** * Extract variable references from text (async version) * Note: This is needed for proper async handling with the parser. * @param text Text to extract references from * @returns Promise resolving to array of variable names */ extractReferencesAsync(text: string): Promise<string[]>; /** * Debug helper to trace field access resolution * @param obj The object to access fields on * @param fields Array of field names to access * @param context Resolution context * @returns Detailed debug information about field access */ private debugFieldAccess; /** * Gets a variable from the state service * @param name The variable name * @param context The resolution context * @returns The variable value */ private getVariable; /** * Track a variable resolution attempt if tracker is available * @private */ private trackResolutionAttempt; resolveFieldAccess(variableName: string, fieldPath: string, context: ResolutionContext): Promise<any>; } /** * Interface matching the StructuredPath expected from meld-spec */ interface StructuredPath$1 { raw: string; structured: { segments: string[]; variables?: { special?: string[]; path?: string[]; }; cwd?: boolean; }; normalized?: string; } /** * Service responsible for resolving variables, commands, and paths in different contexts */ declare class ResolutionService implements IResolutionService { private stateService; private fileSystemService; private parserService; private pathService; private textResolver; private dataResolver; private pathResolver; private commandResolver; private contentResolver; private variableReferenceResolver; private resolutionTracker?; constructor(stateService: IStateService, fileSystemService: IFileSystemService, parserService: IParserService, pathService: IPathService); /** * Parse a string into AST nodes for resolution */ private parseForResolution; /** * Resolve text variables in a string */ resolveText(text: string, context: ResolutionContext): Promise<string>; /** * Resolve data variables and fields */ resolveData(ref: string, context: ResolutionContext): Promise<any>; /** * Resolve path variables */ resolvePath(path: string, context: ResolutionContext): Promise<string>; /** * Resolve command references */ resolveCommand(cmd: string, args: string[], context: ResolutionContext): Promise<string>; /** * Resolve content from a file path */ resolveFile(path: string): Promise<string>; /** * Resolve raw content nodes, preserving formatting but skipping comments */ resolveContent(nodes: MeldNode[], context: ResolutionContext): Promise<string>; /** * Resolve any value based on the provided context rules */ resolveInContext(value: string | StructuredPath$1, context: ResolutionContext): Promise<string>; /** * Resolve variables within a string value * @internal Used by resolveInContext */ private resolveVariables; /** * Validate that resolution is allowed in the given context */ validateResolution(value: string | StructuredPath$1, context: ResolutionContext): Promise<void>; /** * Check for circular variable references */ detectCircularReferences(value: string): Promise<void>; /** * Extract a section from content by its heading * @param content The content to extract the section from * @param heading The heading text to search for * @param fuzzy Optional fuzzy matching threshold (0-1, where 1 is exact match, defaults to 0.7) * * NOTE: This implementation contains workarounds for limitations in the llmxml library. * See dev/LLMXML-IMPROVEMENTS.md for details about planned improvements to the library * instead of maintaining these workarounds. * * Current workarounds include: * 1. Manual section extraction when llmxml fails * 2. Error reporting with available headings * 3. Configurable fuzzy matching threshold */ extractSection(content: string, heading: string, fuzzy?: number): Promise<string>; /** * Extract all headings from content for error reporting * This functionality should ideally be provided by the llmxml library * @private * @todo Move this functionality into llmxml */ private extractHeadings; /** * Manual section extraction as a fallback when llmxml fails * This is a workaround for limitations in the llmxml library * @private * @todo Remove once llmxml reliability is improved */ private manualSectionExtraction; private calculateSimilarity; private nodesToString; /** * Resolve a structured path to an absolute path * @private */ private resolveStructuredPath; /** * Get the variable reference resolver */ getVariableResolver(): VariableReferenceResolver; /** * Enable tracking of variable resolution attempts * @param config Configuration for the resolution tracker */ enableResolutionTracking(config: Partial<ResolutionTrackingConfig>): void; /** * Get the resolution tracker for debugging * @returns The current resolution tracker or undefined if not enabled */ getResolutionTracker(): VariableResolutionTracker | undefined; } /** * Service for validating and normalizing paths */ declare class PathService implements IPathService { private fs; private parser; private testMode; private homePath; private projectPath; private projectPathResolver; private projectPathResolved; constructor(); /** * Initialize the path service with a file system service */ initialize(fileSystem: IFileSystemService, parser?: IParserService): void; /** * Enable test mode for path operations */ enableTestMode(): void; /** * Disable test mode for path operations */ disableTestMode(): void; /** * Check if test mode is enabled */ isTestMode(): boolean; /** * Set home path for testing */ setHomePath(path: string): void; /** * Set project path for testing */ setProjectPath(path: string): void; /** * Get the home path */ getHomePath(): string; /** * Get the project path */ getProjectPath(): string; /** * Resolve the project path using the ProjectPathResolver */ resolveProjectPath(): Promise<string>; /** * Convert a string path to a structured path using the parser service * @private */ private parsePathToStructured; /** * Validate a structured path according to Meld's path rules * @private */ private validateStructuredPath; /** * Resolve a structured path to its absolute form * @private */ private resolveStructuredPath; /** * Resolve a path to its absolute form */ resolvePath(filePath: string | StructuredPath, baseDir?: string): string; /** * Synchronous version of validateStructuredPath * @private */ private validateStructuredPathSync; /** * Validate a path against a set of constraints */ validatePath(filePath: string | StructuredPath, options?: PathOptions): Promise<string>; /** * Normalize a path by resolving '..' and '.' segments */ normalizePath(filePath: string): string; /** * Join multiple path segments together */ join(...paths: string[]): string; /** * Get the directory name of a path */ dirname(pathStr: string): string; /** * Get the base name of a path */ basename(pathStr: string): string; /** * Validate a path string that follows Meld path syntax rules * This is a convenience method that passes the location information to validatePath */ validateMeldPath(path: string, location?: Location): void; /** * Normalize a path string (replace backslashes with forward slashes) */ normalizePathString(path: string): string; } declare enum ErrorSeverity { Fatal = "fatal", Recoverable = "recoverable", Warning = "warning" } interface MeldErrorOptions { cause?: Error; code?: string; filePath?: string; severity?: ErrorSeverity; context?: any; } interface SerializedMeldError { name: string; message: string; code?: string; filePath?: string; cause?: string; severity: ErrorSeverity; context?: any; } /** * Base class for all Meld errors */ declare class MeldError extends Error { readonly code?: string; readonly filePath?: string; private readonly errorCause?; readonly severity: ErrorSeverity; readonly context?: any; constructor(message: string, options?: MeldErrorOptions); /** * Custom serialization to avoid circular references and include only essential info */ toJSON(): SerializedMeldError; /** * Check if this error can be treated as a warning in permissive mode */ canBeWarning(): boolean; /** * Wrap an unknown error in a MeldError */ static wrap(error: unknown, message?: string, severity?: ErrorSeverity): MeldError; } interface DirectiveLocation { line: number; column: number; filePath?: string; } interface MeldDirectiveErrorOptions { location?: DirectiveLocation; code?: string; cause?: Error; severity?: ErrorSeverity; context?: any; } declare class MeldDirectiveError extends MeldError { readonly directiveKind: string; readonly location?: DirectiveLocation; constructor(message: string, directiveKind: string, options?: MeldDirectiveErrorOptions); } /** * Error codes for directive failures */ declare enum DirectiveErrorCode { VALIDATION_FAILED = "VALIDATION_FAILED", RESOLUTION_FAILED = "RESOLUTION_FAILED", EXECUTION_FAILED = "EXECUTION_FAILED", HANDLER_NOT_FOUND = "HANDLER_NOT_FOUND", FILE_NOT_FOUND = "FILE_NOT_FOUND", CIRCULAR_REFERENCE = "CIRCULAR_REFERENCE", VARIABLE_NOT_FOUND = "VARIABLE_NOT_FOUND", STATE_ERROR = "STATE_ERROR", INVALID_CONTEXT = "INVALID_CONTEXT", SECTION_NOT_FOUND = "SECTION_NOT_FOUND" } /** * Map of directive error codes to severity levels */ declare const ValidationErrorSeverity: Record<DirectiveErrorCode, ErrorSeverity>; declare class ValidationService implements IValidationService { private validators; constructor(); /** * Validate a directive node against its schema and constraints * @throws {MeldDirectiveError} If validation fails */ validate(node: DirectiveNode): Promise<void>; /** * Register a validator for a directive kind */ registerValidator(kind: string, validator: (node: DirectiveNode) => Promise<void>): void; /** * Remove a validator for a directive kind */ removeValidator(kind: string): void; /** * Check if a validator exists for a directive kind */ hasValidator(kind: string): boolean; /** * Get all registered directive kinds */ getRegisteredDirectiveKinds(): string[]; } /** * Service for tracking and detecting circular imports in Meld files. */ interface ICircularityService { /** * Called at the start of an import operation. * @throws {MeldImportError} If a circular import is detected */ beginImport(filePath: string): void; /** * Called after import is finished (success or failure). * Removes filePath from the import stack. */ endImport(filePath: string): void; /** * Check if a file is currently in the import stack. */ isInStack(filePath: string): boolean; /** * Get the current import stack. */ getImportStack(): string[]; /** * Clear the import stack. */ reset(): void; } declare class CircularityService implements ICircularityService { private importStack; beginImport(filePath: string): void; endImport(filePath: string): void; isInStack(filePath: string): boolean; getImportStack(): string[]; reset(): void; } /** * Result of directive execution */ interface DirectiveResult { /** The updated state after directive execution */ state: IStateService; /** Optional replacement node for transformation */ replacement?: MeldNode; } interface ILogger { debug: (message: string, ...args: any[]) => void; info: (message: string, ...args: any[]) => void; warn: (message: string, ...args: any[]) => void; error: (message: string, ...args: any[]) => void; } declare class MeldLLMXMLError extends Error { readonly code: string; readonly details?: any | undefined; constructor(message: string, code: string, details?: any | undefined); } /** * Service responsible for handling directives */ declare class DirectiveService implements IDirectiveService { private validationService?; private stateService?; private pathService?; private fileSystemService?; private parserService?; private interpreterService?; private circularityService?; private resolutionService?; private initialized; private logger; private handlers; constructor(logger?: ILogger); initialize(validationService: IValidationService, stateService: IStateService, pathService: IPathService, fileSystemService: IFileSystemService, parserService: IParserService, interpreterService: IInterpreterService, circularityService: ICircularityService, resolutionService: IResolutionService): void; /** * Register all default directive handlers */ registerDefaultHandlers(): void; /** * Register a new directive handler */ registerHandler(handler: IDirectiveHandler): void; /** * Handle a directive node */ handleDirective(node: DirectiveNode, context: DirectiveContext): Promise<IStateService>; /** * Process multiple directives in sequence */ processDirectives(nodes: DirectiveNode[], parentContext?: DirectiveContext): Promise<IStateService>; /** * Create execution context for a directive */ private createContext; /** * Update the interpreter service reference */ updateInterpreterService(interpreterService: IInterpreterService): void; /** * Check if a handler exists for a directive kind */ hasHandler(kind: string): boolean; /** * Validate a directive node */ validateDirective(node: DirectiveNode): Promise<void>; /** * Create a child context for nested directives */ createChildContext(parentContext: DirectiveContext, filePath: string): DirectiveContext; supportsDirective(kind: string): boolean; getSupportedDirectives(): string[]; private ensureInitialized; private handleTextDirective; private handleDataDirective; private handleImportDirective; private extractSection; private calculateSimilarity; private handleEmbedDirective; /** * Process a directive node, validating and executing it * Values in the directive will already be interpolated by meld-ast * @returns The updated state after directive execution * @throws {MeldDirectiveError} If directive processing fails */ processDirective(node: DirectiveNode, context: DirectiveContext): Promise<IStateService>; } type FormatConverter = (nodes: MeldNode[], state: IStateService, options?: OutputOptions) => Promise<string>; declare class OutputService implements IOutputService { private formatters; private state; private resolutionService; canAccessTransformedNodes(): boolean; constructor(); initialize(state: IStateService, resolutionService?: IResolutionService): void; convert(nodes: MeldNode[], state: IStateService, format: OutputFormat, options?: OutputOptions): Promise<string>; registerFormat(format: string, converter: FormatConverter): void; supportsFormat(format: string): boolean; getSupportedFormats(): string[]; /** * Helper method to safely extract string content from various node types * ensuring proper type safety */ private getTextContentFromNode; private convertToMarkdown; private convertToXML; private formatStateVariables; private nodeToMarkdown; private nodeToXML; private codeFenceToMarkdown; private codeFenceToXML; private directiveToMarkdown; private directiveToXML; } /** * @package * Interface for state visualization service. * * @remarks * Provides visualization capabilities for state hierarchies, * transitions, relationships, and metrics. Supports multiple * output formats for different use cases (e.g., debug, analysis). */ /** * Supported visualization formats */ type VisualizationFormat = 'mermaid' | 'dot' | 'json'; /** * Node styling options for visualizations */ interface NodeStyle { shape?: 'box' | 'circle' | 'diamond'; color?: string; label?: string; tooltip?: string; } /** * Edge styling options for visualizations */ interface EdgeStyle { style?: 'solid' | 'dashed' | 'dotted'; color?: string; label?: string; tooltip?: string; } /** * Configuration for generating visualizations */ interface VisualizationConfig { format: VisualizationFormat; includeMetadata?: boolean; includeTimestamps?: boolean; styleNodes?: (metadata: StateMetadata) => NodeStyle; styleEdges?: (relationship: StateRelationship) => EdgeStyle; timeRange?: { start?: number; end?: number; }; } /** * Configuration for context visualizations */ interface ContextVisualizationConfig extends VisualizationConfig { includeVars?: boolean; filterToRelevantVars?: boolean; highlightBoundaries?: boolean; includeBoundaryTypes?: boolean; includeFilePaths?: boolean; } /** * Basic metrics about the state system */ interface StateMetrics { totalStates: number; statesByType: Record<string, number>; averageTransformationsPerState: number; maxTransformationChainLength: number; averageChildrenPerState: number; maxTreeDepth: number; operationFrequency: Record<string, number>; } /** * Core state visualization service interface */ interface IStateVisualizationService { /** * Generate a hierarchical view of state relationships * @param rootStateId - The root state to start visualization from * @param config - Visualization configuration * @returns Visualization in the specified format */ generateHierarchyView(rootStateId: string, config: VisualizationConfig): string; /** * Generate a transition diagram showing state transformations * @param stateId - The state to show transitions for * @param config - Visualization configuration * @returns Visualization in the specified format */ generateTransitionDiagram(stateId: string, config: VisualizationConfig): string; /** * Generate a relationship graph showing state connections * @param stateIds - The states to include in the graph * @param config - Visualization configuration * @returns Visualization in the specified format */ generateRelationshipGraph(stateIds: string[], config: VisualizationConfig): string; /** * Generate a timeline view of state operations * @param stateIds - The states to include in the timeline * @param config - Visualization configuration * @returns Visualization in the specified format */ generateTimeline(stateIds: string[], config: VisualizationConfig): string; /** * Calculate and return metrics about the state system * @param timeRange - Optional time range to limit metrics to * @returns Object containing various metrics */ getMetrics(timeRange?: { start: number; end: number; }): StateMetrics; /** * Export the complete state graph in the specified format * @param config - Visualization configuration * @returns Complete state graph visualization */ exportStateGraph(config: VisualizationConfig): string; /** * Generate a context hierarchy visualization showing context boundaries * @param rootStateId - The root state to start visualization from * @param config - Context visualization configuration * @returns Context hierarchy visualization in the specified format */ visualizeContextHierarchy(rootStateId: string, config: ContextVisualizationConfig): string; /** * Generate a variable propagation visualization showing how variables move across contexts * @param variableName - The name of the variable to track propagation for * @param rootStateId - Optional root state to limit visualization scope * @param config - Context visualization configuration * @returns Variable propagation visualization in the specified format */ visualizeVariablePropagation(variableName: string, rootStateId?: string, config?: ContextVisualizationConfig): string; /** * Generate a combined context and variable flow visualization * @param rootStateId - The root state to start visualization from * @param config - Context visualization configuration * @returns Combined context and variable flow visualization */ visualizeContextsAndVariableFlow(rootStateId: string, config: ContextVisualizationConfig): string; /** * Generate a resolution path timeline visualization for a specific variable * @p