@fulmenhq/tsfulmen 0.3.1 → 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/schema/ajv-formats.ts","../../src/schema/errors.ts","../../src/schema/utils.ts","../../src/schema/goneat-bridge.ts","../../src/schema/normalizer.ts","../../src/schema/registry.ts","../../src/telemetry/counter.ts","../../src/telemetry/gauge.ts","../../src/telemetry/taxonomy.ts","../../src/telemetry/histogram.ts","../../src/telemetry/registry.ts","../../src/telemetry/types.ts","../../src/telemetry/validators.ts","../../src/telemetry/index.ts","../../src/schema/validator.ts","../../src/schema/cli.ts","../../src/schema/export.ts","../../src/schema/index.ts","../../src/config/env-alias.ts","../../src/config/errors.ts","../../src/config/loader.ts","../../src/config/paths.ts","../../src/config/index.ts"],"names":["join","readFile","parseYaml","init_registry","fileURLToPath","__dirname","dirname","parseYAML","access","mkdir","extname"],"mappings":"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","file":"index.js","sourcesContent":["import type Ajv from \"ajv\";\nimport addFormats from \"ajv-formats\";\n\nexport interface FulmenAjvFormatsOptions {\n mode?: \"fast\" | \"full\";\n formats?: string[];\n}\n\nconst DEFAULT_FORMATS = [\n \"date-time\",\n \"email\",\n \"hostname\",\n \"ipv4\",\n \"ipv6\",\n \"uri\",\n \"uri-reference\",\n \"uuid\",\n];\n\n/**\n * Apply Fulmen-standard AJV format support.\n *\n * Useful when configuring AJV in other frameworks (e.g. Fastify) so JSON Schema\n * `format` keywords are enforced consistently.\n */\nexport function applyFulmenAjvFormats(ajv: Ajv, options: FulmenAjvFormatsOptions = {}): Ajv {\n const mode = options.mode ?? \"fast\";\n const formats = options.formats ?? DEFAULT_FORMATS;\n\n // ajv-formats types use a string-literal union; allow callers to supply strings.\n // The `as never` on ajv works around ajv-formats bundling its own older ajv types\n // that diverge from ajv@8.18+ (CodeKeywordDefinition.code parameter incompatibility).\n addFormats(ajv as never, { mode, formats: formats as unknown as never[] });\n return ajv;\n}\n","/**\n * Schema validation errors - implements Fulmen Schema Validation Standard\n */\n\nimport type { SchemaSource, SchemaValidationDiagnostic } from \"./types.js\";\n\n/**\n * Export error reason enum for type-safe error categorization\n */\nexport enum ExportErrorReason {\n FILE_EXISTS = \"FILE_EXISTS\",\n WRITE_FAILED = \"WRITE_FAILED\",\n INVALID_FORMAT = \"INVALID_FORMAT\",\n PROVENANCE_FAILED = \"PROVENANCE_FAILED\",\n UNKNOWN = \"UNKNOWN\",\n}\n\n/**\n * Base error class for schema validation operations\n */\nexport class SchemaValidationError extends Error {\n constructor(\n message: string,\n public schemaId?: string,\n public diagnostics: SchemaValidationDiagnostic[] = [],\n public source?: SchemaSource,\n public cause?: Error,\n ) {\n super(message);\n this.name = \"SchemaValidationError\";\n\n // Maintains proper stack trace for where our error was thrown (only available on V8)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, SchemaValidationError);\n }\n }\n\n /**\n * Create error for schema not found\n */\n static schemaNotFound(schemaId: string): SchemaValidationError {\n return new SchemaValidationError(`Schema not found: ${schemaId}`, schemaId);\n }\n\n /**\n * Create error for invalid schema input\n */\n static invalidSchemaInput(source: SchemaSource, details: string): SchemaValidationError {\n return new SchemaValidationError(`Invalid schema input: ${details}`, undefined, [], source);\n }\n\n /**\n * Create error for validation failure\n */\n static validationFailed(\n schemaId: string,\n diagnostics: SchemaValidationDiagnostic[],\n source?: SchemaSource,\n ): SchemaValidationError {\n const errorCount = diagnostics.filter((d) => d.severity === \"ERROR\").length;\n const warningCount = diagnostics.filter((d) => d.severity === \"WARN\").length;\n\n const message = `Schema validation failed: ${errorCount} error(s), ${warningCount} warning(s)`;\n\n return new SchemaValidationError(message, schemaId, diagnostics, source);\n }\n\n /**\n * Create error for goneat binary not found\n */\n static goneatNotFound(goneatPath?: string): SchemaValidationError {\n const pathInfo = goneatPath ? ` at ${goneatPath}` : \"\";\n return new SchemaValidationError(\n `Goneat binary not found${pathInfo}. Falling back to AJV validation.`,\n );\n }\n\n /**\n * Create error for goneat execution failure\n */\n static goneatExecutionFailed(error: Error): SchemaValidationError {\n return new SchemaValidationError(\n \"Goneat execution failed. Falling back to AJV validation.\",\n undefined,\n [],\n undefined,\n error,\n );\n }\n\n /**\n * Create error for empty schema input\n */\n static emptySchemaInput(source?: SchemaSource): SchemaValidationError {\n return new SchemaValidationError(\"Schema content is empty\", undefined, [], source);\n }\n\n /**\n * Create error for parse failure\n */\n static parseFailed(source: SchemaSource, error: Error): SchemaValidationError {\n return new SchemaValidationError(\n `Failed to parse schema: ${error.message}`,\n undefined,\n [],\n source,\n error,\n );\n }\n\n /**\n * Create error for encoding failure\n */\n static encodingFailed(source: SchemaSource, error: Error): SchemaValidationError {\n return new SchemaValidationError(\n `Failed to encode schema: ${error.message}`,\n undefined,\n [],\n source,\n error,\n );\n }\n\n /**\n * Create error for registry operation failure\n */\n static registryError(operation: string, details: string): SchemaValidationError {\n return new SchemaValidationError(`Schema registry ${operation} failed: ${details}`);\n }\n\n /**\n * Format error for display\n */\n format(): string {\n let output = this.message;\n\n if (this.schemaId) {\n output += `\\nSchema ID: ${this.schemaId}`;\n }\n\n if (this.diagnostics.length > 0) {\n output += \"\\n\\nValidation Issues:\";\n this.diagnostics.forEach((diag, index) => {\n output += `\\n ${index + 1}. [${diag.severity}] ${diag.message}`;\n if (diag.pointer) {\n output += ` at ${diag.pointer}`;\n }\n if (diag.keyword) {\n output += ` (keyword: ${diag.keyword})`;\n }\n if (diag.source) {\n output += ` [${diag.source}]`;\n }\n });\n }\n\n if (this.source) {\n output += `\\n\\nSource: ${this.source.type}`;\n if (this.source.id) {\n output += ` (${this.source.id})`;\n }\n }\n\n return output;\n }\n\n /**\n * Convert to JSON representation\n */\n toJSON(): {\n name: string;\n message: string;\n schemaId?: string;\n diagnostics: SchemaValidationDiagnostic[];\n source?: SchemaSource;\n cause?: string;\n } {\n return {\n name: this.name,\n message: this.message,\n schemaId: this.schemaId,\n diagnostics: this.diagnostics,\n source: this.source,\n cause: this.cause?.message,\n };\n }\n}\n\n/**\n * Error class for schema export operations\n */\nexport class SchemaExportError extends SchemaValidationError {\n constructor(\n message: string,\n public reason: ExportErrorReason,\n public schemaId?: string,\n public outPath?: string,\n public cause?: Error,\n ) {\n super(message, schemaId, [], undefined, cause);\n this.name = \"SchemaExportError\";\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, SchemaExportError);\n }\n }\n\n /**\n * Create error for file already exists\n */\n static fileExists(outPath: string): SchemaExportError {\n return new SchemaExportError(\n `Output file already exists: ${outPath}. Use overwrite option to replace.`,\n ExportErrorReason.FILE_EXISTS,\n undefined,\n outPath,\n );\n }\n\n /**\n * Create error for invalid export format\n */\n static invalidFormat(format: string, outPath: string): SchemaExportError {\n return new SchemaExportError(\n `Invalid export format: ${format}. Must be 'json' or 'yaml'.`,\n ExportErrorReason.INVALID_FORMAT,\n undefined,\n outPath,\n );\n }\n\n /**\n * Create error for write failure\n */\n static writeFailed(outPath: string, error: Error): SchemaExportError {\n return new SchemaExportError(\n `Failed to write schema to ${outPath}: ${error.message}`,\n ExportErrorReason.WRITE_FAILED,\n undefined,\n outPath,\n error,\n );\n }\n\n /**\n * Create error for provenance extraction failure\n */\n static provenanceFailed(details: string, error?: Error): SchemaExportError {\n return new SchemaExportError(\n `Failed to extract provenance metadata: ${details}`,\n ExportErrorReason.PROVENANCE_FAILED,\n undefined,\n undefined,\n error,\n );\n }\n}\n","/**\n * Schema validation utilities - helper functions for formatting and validation\n */\n\nimport { SchemaValidationError } from \"./errors.js\";\nimport type { SchemaValidationDiagnostic, SchemaValidationResult } from \"./types.js\";\n\n/**\n * Format validation diagnostics for display\n */\nexport function formatDiagnostics(diagnostics: SchemaValidationDiagnostic[]): string {\n if (diagnostics.length === 0) {\n return \"No validation issues found.\";\n }\n\n const lines: string[] = [];\n const errors = diagnostics.filter((d) => d.severity === \"ERROR\");\n const warnings = diagnostics.filter((d) => d.severity === \"WARN\");\n\n if (errors.length > 0) {\n lines.push(`❌ ${errors.length} error(s) found:`);\n errors.forEach((diag, index) => {\n lines.push(` ${index + 1}. ${diag.message}`);\n if (diag.pointer) {\n lines.push(` at ${diag.pointer}`);\n }\n if (diag.keyword) {\n lines.push(` keyword: ${diag.keyword}`);\n }\n });\n }\n\n if (warnings.length > 0) {\n lines.push(\"\");\n lines.push(`⚠️ ${warnings.length} warning(s) found:`);\n warnings.forEach((diag, index) => {\n lines.push(` ${index + 1}. ${diag.message}`);\n if (diag.pointer) {\n lines.push(` at ${diag.pointer}`);\n }\n });\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Format validation result for display\n */\nexport function formatValidationResult(result: SchemaValidationResult): string {\n if (result.valid) {\n return \"✅ Validation passed\";\n }\n\n const output: string[] = [];\n output.push(\"❌ Validation failed\");\n output.push(formatDiagnostics(result.diagnostics));\n output.push(`\\nSource: ${result.source}`);\n\n return output.join(\"\\n\");\n}\n\n/**\n * Check if value is a SchemaValidationError\n */\nexport function isValidationError(error: unknown): error is SchemaValidationError {\n return error instanceof SchemaValidationError;\n}\n\n/**\n * Extract validation result from error or return success\n */\nexport function extractValidationResult(error: unknown): {\n valid: boolean;\n diagnostics: SchemaValidationDiagnostic[];\n source: \"ajv\" | \"goneat\";\n} {\n if (isValidationError(error)) {\n return {\n valid: false,\n diagnostics: error.diagnostics,\n source: error.diagnostics[0]?.source || \"ajv\",\n };\n }\n\n return {\n valid: true,\n diagnostics: [],\n source: \"ajv\",\n };\n}\n\n/**\n * Normalize JSON pointer path for display\n */\nexport function normalizePointer(pointer: string): string {\n if (pointer === \"\") {\n return \"root\";\n }\n return pointer.replace(/^\\//, \"\").replace(/\\//g, \".\");\n}\n\n/**\n * Create a validation diagnostic\n */\nexport function createDiagnostic(\n pointer: string,\n message: string,\n keyword: string,\n severity: \"ERROR\" | \"WARN\" = \"ERROR\",\n source: \"ajv\" | \"goneat\" = \"ajv\",\n data?: unknown,\n): SchemaValidationDiagnostic {\n return {\n pointer,\n message,\n keyword,\n severity,\n source,\n data,\n };\n}\n\n/**\n * Group diagnostics by severity\n */\nexport function groupDiagnosticsBySeverity(diagnostics: SchemaValidationDiagnostic[]): {\n errors: SchemaValidationDiagnostic[];\n warnings: SchemaValidationDiagnostic[];\n} {\n return {\n errors: diagnostics.filter((d) => d.severity === \"ERROR\"),\n warnings: diagnostics.filter((d) => d.severity === \"WARN\"),\n };\n}\n\n/**\n * Count diagnostics by severity\n */\nexport function countDiagnostics(diagnostics: SchemaValidationDiagnostic[]): {\n total: number;\n errors: number;\n warnings: number;\n} {\n const grouped = groupDiagnosticsBySeverity(diagnostics);\n return {\n total: diagnostics.length,\n errors: grouped.errors.length,\n warnings: grouped.warnings.length,\n };\n}\n","/**\n * Goneat bridge - Optional integration for CLI-only goneat validation\n *\n * Provides goneat validation as an opt-in alternative for CLI exploration.\n * NOT used by library consumers - AJV validation is the primary implementation.\n */\n\nimport { spawn } from \"node:child_process\";\nimport { access } from \"node:fs/promises\";\nimport type { SchemaValidationDiagnostic, SchemaValidationResult } from \"./types.js\";\nimport { createDiagnostic } from \"./utils.js\";\n\n/**\n * Goneat validation output structure\n */\ninterface GoneatValidationOutput {\n valid: boolean;\n errors?: Array<{\n path: string;\n message: string;\n keyword?: string;\n }>;\n}\n\n/**\n * Detect goneat binary location\n */\nexport async function detectGoneat(customPath?: string): Promise<string | null> {\n // Try custom path first\n if (customPath) {\n try {\n await access(customPath);\n return customPath;\n } catch {\n return null;\n }\n }\n\n // Try GONEAT_PATH environment variable\n if (process.env.GONEAT_PATH) {\n try {\n await access(process.env.GONEAT_PATH);\n return process.env.GONEAT_PATH;\n } catch {\n // Continue to next option\n }\n }\n\n // Try local bin/goneat\n try {\n await access(\"./bin/goneat\");\n return \"./bin/goneat\";\n } catch {\n // Continue to next option\n }\n\n // Try system PATH (assume 'goneat' command available)\n return \"goneat\";\n}\n\n/**\n * Check if goneat is available\n *\n * If goneatPath is provided, use it directly to test availability.\n * Otherwise, detect goneat location first.\n */\nexport async function isGoneatAvailable(goneatPath?: string): Promise<boolean> {\n let pathToTest: string | null;\n\n if (goneatPath) {\n // Use provided path directly - don't re-detect\n // This allows testing 'goneat' command from PATH\n pathToTest = goneatPath;\n } else {\n // Detect goneat location\n pathToTest = await detectGoneat();\n if (!pathToTest) return false;\n }\n\n return new Promise((resolve) => {\n const proc = spawn(pathToTest as string, [\"version\"], { stdio: \"ignore\" });\n\n // Timeout after 5 seconds to prevent hanging in CI\n const timeout = setTimeout(() => {\n proc.kill();\n resolve(false);\n }, 5000);\n\n proc.on(\"close\", (code) => {\n clearTimeout(timeout);\n resolve(code === 0);\n });\n proc.on(\"error\", () => {\n clearTimeout(timeout);\n resolve(false);\n });\n });\n}\n\n/**\n * Run goneat schema validation (CLI-only, opt-in)\n *\n * This is NOT used by library validation - it's purely for CLI comparison.\n * Library users get full AJV validation without goneat dependency.\n */\nexport async function runGoneatValidation(\n schemaPath: string,\n dataPath: string,\n goneatPath?: string,\n): Promise<SchemaValidationResult> {\n const detected = await detectGoneat(goneatPath);\n\n if (!detected) {\n return {\n valid: false,\n diagnostics: [\n createDiagnostic(\n \"\",\n \"goneat binary not found. Install goneat or specify path with --goneat-path\",\n \"goneat-unavailable\",\n \"ERROR\",\n \"goneat\",\n ),\n ],\n source: \"goneat\",\n };\n }\n\n // Check availability using the detected path directly\n if (!(await isGoneatAvailable(detected))) {\n return {\n valid: false,\n diagnostics: [\n createDiagnostic(\n \"\",\n `goneat binary found at '${detected}' but not executable or version check failed`,\n \"goneat-not-executable\",\n \"ERROR\",\n \"goneat\",\n ),\n ],\n source: \"goneat\",\n };\n }\n\n return new Promise((resolve) => {\n const args = [\n \"schema\",\n \"validate\",\n \"--schema\",\n schemaPath,\n \"--data\",\n dataPath,\n \"--format\",\n \"json\",\n ];\n const proc = spawn(detected, args);\n\n let stdout = \"\";\n let stderr = \"\";\n\n proc.stdout.on(\"data\", (data) => {\n stdout += data.toString();\n });\n\n proc.stderr.on(\"data\", (data) => {\n stderr += data.toString();\n });\n\n proc.on(\"close\", (code: number | null) => {\n // Parse goneat output\n let output: GoneatValidationOutput;\n\n try {\n output = JSON.parse(stdout) as GoneatValidationOutput;\n } catch {\n // Failed to parse output, treat as error\n resolve({\n valid: false,\n diagnostics: [\n createDiagnostic(\n \"\",\n `goneat validation failed: ${stderr || \"unknown error\"}`,\n \"goneat-error\",\n \"ERROR\",\n \"goneat\",\n ),\n ],\n source: \"goneat\",\n });\n return;\n }\n\n // Convert goneat errors to our diagnostic format\n const diagnostics: SchemaValidationDiagnostic[] =\n output.errors?.map((error) =>\n createDiagnostic(\n error.path || \"\",\n error.message,\n error.keyword || \"validation\",\n \"ERROR\",\n \"goneat\",\n ),\n ) || [];\n\n resolve({\n valid: code === 0 && output.valid,\n diagnostics,\n source: \"goneat\",\n });\n });\n\n proc.on(\"error\", (error) => {\n resolve({\n valid: false,\n diagnostics: [\n createDiagnostic(\n \"\",\n `Failed to execute goneat: ${error.message}`,\n \"goneat-spawn-error\",\n \"ERROR\",\n \"goneat\",\n ),\n ],\n source: \"goneat\",\n });\n });\n });\n}\n","/**\n * Schema normalizer - implements schema normalization per Fulmen standard\n *\n * Provides utilities for canonicalizing and comparing schemas across\n * JSON and YAML formats with comment preservation and deterministic output.\n */\n\nimport { parse as parseYAML } from \"yaml\";\nimport { SchemaValidationError } from \"./errors.js\";\nimport type { SchemaInput, SchemaNormalizationOptions } from \"./types.js\";\n\n/**\n * Parse schema input to object\n */\nfunction parseSchemaInput(input: SchemaInput): Record<string, unknown> {\n if (!input) {\n throw SchemaValidationError.parseFailed(\n { type: \"string\", content: \"\" },\n new Error(\"schema content is empty\"),\n );\n }\n\n try {\n if (typeof input === \"string\") {\n // Try JSON first, fall back to YAML\n try {\n return JSON.parse(input) as Record<string, unknown>;\n } catch {\n return parseYAML(input) as Record<string, unknown>;\n }\n }\n\n if (Buffer.isBuffer(input)) {\n const content = input.toString(\"utf-8\");\n try {\n return JSON.parse(content) as Record<string, unknown>;\n } catch {\n return parseYAML(content) as Record<string, unknown>;\n }\n }\n\n // Already an object\n return input as Record<string, unknown>;\n } catch (error) {\n throw SchemaValidationError.parseFailed(\n {\n type: typeof input === \"string\" ? \"string\" : \"object\",\n content: typeof input === \"string\" ? input : JSON.stringify(input),\n },\n error as Error,\n );\n }\n}\n\n/**\n * Sort object keys recursively in lexicographical order\n */\nfunction sortObjectKeys(obj: unknown): unknown {\n if (obj === null || typeof obj !== \"object\") {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return obj.map(sortObjectKeys);\n }\n\n const sorted: Record<string, unknown> = {};\n const keys = Object.keys(obj).sort();\n\n for (const key of keys) {\n sorted[key] = sortObjectKeys((obj as Record<string, unknown>)[key]);\n }\n\n return sorted;\n}\n\n/**\n * Normalize schema to canonical JSON format\n *\n * Per Fulmen Schema Normalization Standard:\n * - Accepts YAML or JSON input\n * - Strips comments while preserving semantic structure\n * - Sorts keys lexicographically\n * - Produces deterministic, pretty-printed JSON (or compact if requested)\n */\nexport function normalizeSchema(\n input: SchemaInput,\n options: SchemaNormalizationOptions = {},\n): string {\n try {\n // Parse input to object\n const parsed = parseSchemaInput(input);\n\n // Sort keys recursively\n const sorted = sortObjectKeys(parsed);\n\n // Serialize to JSON with optional compact mode\n if (options.compact) {\n return JSON.stringify(sorted);\n }\n\n // Default: pretty-printed with 2-space indentation\n return JSON.stringify(sorted, null, 2);\n } catch (error) {\n if (error instanceof SchemaValidationError) {\n throw error;\n }\n throw SchemaValidationError.parseFailed(\n {\n type: typeof input === \"string\" ? \"string\" : \"object\",\n content: typeof input === \"string\" ? input : JSON.stringify(input),\n },\n error as Error,\n );\n }\n}\n\n/**\n * Compare two schemas for semantic equality\n *\n * Normalizes both schemas and compares the canonical JSON output.\n * Returns equality result along with normalized versions for debugging.\n */\nexport function compareSchemas(\n schemaA: SchemaInput,\n schemaB: SchemaInput,\n options: SchemaNormalizationOptions = {},\n): { equal: boolean; normalizedA: string; normalizedB: string } {\n const normalizedA = normalizeSchema(schemaA, options);\n const normalizedB = normalizeSchema(schemaB, options);\n\n return {\n equal: normalizedA === normalizedB,\n normalizedA,\n normalizedB,\n };\n}\n","/**\n * Schema registry - implements schema discovery and metadata extraction\n */\n\nimport { access, readFile } from \"node:fs/promises\";\nimport { dirname, extname, join, relative } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport glob from \"fast-glob\";\nimport { parse as parseYAML } from \"yaml\";\nimport { SchemaValidationError } from \"./errors.js\";\nimport type { SchemaFormat, SchemaMetadata, SchemaRegistryOptions } from \"./types.js\";\n\n/**\n * Default schema file patterns\n */\nconst DEFAULT_PATTERNS = [\"**/*.schema.json\", \"**/*.schema.yaml\", \"**/*.schema.yml\"];\n\n/**\n * Schema registry class for managing schema discovery and metadata\n */\nexport class SchemaRegistry {\n private schemas: Map<string, SchemaMetadata> = new Map();\n private options: SchemaRegistryOptions;\n\n constructor(options: SchemaRegistryOptions = {}) {\n this.options = {\n baseDir: options.baseDir || this.getDefaultSchemaDir(),\n patterns: options.patterns || DEFAULT_PATTERNS,\n followSymlinks: options.followSymlinks ?? false,\n maxDepth: options.maxDepth ?? 10,\n };\n }\n\n /**\n * Get default schema directory using import.meta.url\n */\n private getDefaultSchemaDir(): string {\n const __filename = fileURLToPath(import.meta.url);\n const __dirname = dirname(__filename);\n // From src/schema/ we need to go up 2 levels to repo root, then into schemas/crucible-ts\n return join(__dirname, \"..\", \"..\", \"schemas\", \"crucible-ts\");\n }\n\n /**\n * Build logical schema ID from file path\n */\n private buildSchemaId(filePath: string, baseDir: string): string {\n const relativePath = relative(baseDir, filePath);\n const withoutExt = relativePath.replace(/\\.(schema\\.(json|yaml|yml))$/, \"\");\n return withoutExt.replace(/\\\\/g, \"/\"); // Normalize path separators\n }\n\n /**\n * Extract schema format from file extension\n */\n private getSchemaFormat(filePath: string): SchemaFormat {\n const ext = extname(filePath).toLowerCase();\n switch (ext) {\n case \".json\":\n return \"json\";\n case \".yaml\":\n case \".yml\":\n return \"yaml\";\n default:\n return \"json\"; // Default fallback\n }\n }\n\n /**\n * Extract metadata from schema file\n */\n private async extractMetadata(filePath: string): Promise<SchemaMetadata> {\n try {\n const content = await readFile(filePath, \"utf-8\");\n const format = this.getSchemaFormat(filePath);\n\n let parsed: Record<string, unknown>;\n if (format === \"yaml\") {\n parsed = parseYAML(content) as Record<string, unknown>;\n } else {\n parsed = JSON.parse(content) as Record<string, unknown>;\n }\n\n const baseDir = this.options.baseDir ?? \"\";\n const relativePath = relative(baseDir, filePath);\n\n return {\n id: this.buildSchemaId(filePath, baseDir),\n path: filePath,\n relativePath: relativePath,\n format,\n version: (parsed.$schema as string) || (parsed.version as string),\n description: (parsed.title as string) || (parsed.description as string),\n schemaDraft: parsed.$schema as string,\n };\n } catch (error) {\n throw SchemaValidationError.registryError(\n \"metadata extraction\",\n `Failed to process ${filePath}: ${(error as Error).message}`,\n );\n }\n }\n\n /**\n * Discover and index all available schemas\n */\n async discoverSchemas(): Promise<void> {\n try {\n const baseDir = this.options.baseDir ?? \"\";\n const patterns = this.options.patterns ?? [];\n\n if (patterns.length === 0) {\n this.schemas.clear();\n return;\n }\n\n const pattern = patterns.map((p) => join(baseDir, p));\n\n // Check if base directory exists\n try {\n await access(baseDir);\n } catch {\n // Base directory doesn't exist, clear registry and return\n this.schemas.clear();\n return;\n }\n\n const files = await glob(pattern, {\n absolute: true,\n followSymbolicLinks: this.options.followSymlinks,\n deep: this.options.maxDepth,\n onlyFiles: true,\n suppressErrors: true, // Don't throw on permission errors\n });\n\n // Clear existing schemas\n this.schemas.clear();\n\n // Process each schema file\n for (const filePath of files) {\n try {\n const metadata = await this.extractMetadata(filePath);\n this.schemas.set(metadata.id, metadata);\n } catch (error) {\n // Log error but continue processing other schemas\n console.warn(`Warning: Failed to process schema ${filePath}:`, error);\n }\n }\n } catch (error) {\n throw SchemaValidationError.registryError(\"discovery\", (error as Error).message);\n }\n }\n\n /**\n * List available schemas with optional prefix filtering\n */\n async listSchemas(prefix?: string): Promise<SchemaMetadata[]> {\n if (this.schemas.size === 0) {\n await this.discoverSchemas();\n }\n\n const schemas = Array.from(this.schemas.values());\n\n if (prefix) {\n return schemas.filter((schema) => schema.id.startsWith(prefix));\n }\n\n return schemas;\n }\n\n /**\n * Get schema by logical ID\n */\n async getSchema(id: string): Promise<SchemaMetadata> {\n if (this.schemas.size === 0) {\n await this.discoverSchemas();\n }\n\n const schema = this.schemas.get(id);\n if (!schema) {\n throw SchemaValidationError.schemaNotFound(id);\n }\n\n return schema;\n }\n\n /**\n * Get schema by file path\n */\n async getSchemaByPath(filePath: string): Promise<SchemaMetadata> {\n if (this.schemas.size === 0) {\n await this.discoverSchemas();\n }\n\n const absolutePath = filePath.startsWith(\"/\") ? filePath : join(process.cwd(), filePath);\n\n for (const schema of this.schemas.values()) {\n if (schema.path === absolutePath) {\n return schema;\n }\n }\n\n throw SchemaValidationError.schemaNotFound(filePath);\n }\n\n /**\n * Check if schema exists\n */\n async hasSchema(id: string): Promise<boolean> {\n if (this.schemas.size === 0) {\n await this.discoverSchemas();\n }\n\n return this.schemas.has(id);\n }\n\n /**\n * Get registry size\n */\n get size(): number {\n return this.schemas.size;\n }\n\n /**\n * Clear registry cache\n */\n clear(): void {\n this.schemas.clear();\n }\n}\n\n/**\n * Global schema registry instance with cached options\n */\nlet globalRegistry: SchemaRegistry | undefined;\nlet globalRegistryOptions: SchemaRegistryOptions | undefined;\n\n/**\n * Check if registry options have changed\n */\nfunction optionsChanged(newOptions?: SchemaRegistryOptions): boolean {\n if (!newOptions && !globalRegistryOptions) return false;\n if (!newOptions || !globalRegistryOptions) return true;\n\n return (\n newOptions.baseDir !== globalRegistryOptions.baseDir ||\n JSON.stringify(newOptions.patterns) !== JSON.stringify(globalRegistryOptions.patterns) ||\n newOptions.followSymlinks !== globalRegistryOptions.followSymlinks ||\n newOptions.maxDepth !== globalRegistryOptions.maxDepth\n );\n}\n\n/**\n * Get or create global schema registry, rebuilding if options change\n */\nexport function getSchemaRegistry(options?: SchemaRegistryOptions): SchemaRegistry {\n if (!globalRegistry || optionsChanged(options)) {\n globalRegistry = new SchemaRegistry(options);\n globalRegistryOptions = options;\n }\n return globalRegistry;\n}\n\n/**\n * List available schemas with optional prefix filtering\n */\nexport async function listSchemas(\n prefix?: string,\n options?: SchemaRegistryOptions,\n): Promise<SchemaMetadata[]> {\n const registry = getSchemaRegistry(options);\n return registry.listSchemas(prefix);\n}\n\n/**\n * Get schema by logical ID\n */\nexport async function getSchema(\n id: string,\n options?: SchemaRegistryOptions,\n): Promise<SchemaMetadata> {\n const registry = getSchemaRegistry(options);\n return registry.getSchema(id);\n}\n\n/**\n * Get schema by file path\n */\nexport async function getSchemaByPath(\n filePath: string,\n options?: SchemaRegistryOptions,\n): Promise<SchemaMetadata> {\n const registry = getSchemaRegistry(options);\n return registry.getSchemaByPath(filePath);\n}\n\n/**\n * Check if schema exists\n */\nexport async function hasSchema(id: string, options?: SchemaRegistryOptions): Promise<boolean> {\n const registry = getSchemaRegistry(options);\n return registry.hasSchema(id);\n}\n","/**\n * Counter metric implementation\n *\n * Monotonically increasing counter for counting events\n */\n\nimport type { MetricName } from \"./types.js\";\n\n/**\n * Counter metric\n *\n * Monotonically increasing value for counting events.\n * Supports labeled metrics (Crucible v0.2.7+).\n * Use for metrics like request counts, error counts, etc.\n */\nexport class Counter {\n private value = 0;\n private labeledValues = new Map<string, number>();\n\n constructor(public readonly name: MetricName) {}\n\n /**\n * Increment counter by delta (default: 1)\n *\n * @param delta - Amount to increment (must be non-negative)\n * @param labels - Optional label dimensions for this observation\n * @throws {Error} If delta is negative\n *\n * @example\n * ```typescript\n * counter.inc(); // Increment unlabeled by 1\n * counter.inc(5); // Increment unlabeled by 5\n * counter.inc(1, { status: '200' }); // Increment labeled instance\n * counter.inc(1, { result: 'success' }); // Different label set\n * ```\n */\n inc(delta = 1, labels?: Record<string, string>): void {\n if (delta < 0) {\n throw new Error(`Counter delta must be non-negative, got: ${delta}`);\n }\n\n if (labels && Object.keys(labels).length > 0) {\n // Labeled metric - track per label combination\n const labelKey = this.serializeLabels(labels);\n const current = this.labeledValues.get(labelKey) || 0;\n this.labeledValues.set(labelKey, current + delta);\n } else {\n // Unlabeled metric\n this.value += delta;\n }\n }\n\n /**\n * Get current counter value (unlabeled)\n */\n getValue(): number {\n return this.value;\n }\n\n /**\n * Get all labeled values\n * @returns Map of serialized label keys to values\n */\n getLabeledValues(): Map<string, number> {\n return new Map(this.labeledValues);\n }\n\n /**\n * Get value for specific label combination\n */\n getValueForLabels(labels: Record<string, string>): number {\n const labelKey = this.serializeLabels(labels);\n return this.labeledValues.get(labelKey) || 0;\n }\n\n /**\n * Reset counter to zero (all label combinations)\n */\n reset(): void {\n this.value = 0;\n this.labeledValues.clear();\n }\n\n /**\n * Serialize labels to deterministic string key\n * Format: key1=value1,key2=value2 (sorted by key)\n */\n private serializeLabels(labels: Record<string, string>): string {\n return Object.entries(labels)\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([k, v]) => `${k}=${v}`)\n .join(\",\");\n }\n}\n","/**\n * Gauge metric implementation\n *\n * Gauge for arbitrary values that can go up and down\n */\n\nimport type { MetricName } from \"./types.js\";\n\n/**\n * Gauge metric\n *\n * Arbitrary value that can increase or decrease.\n * Supports labeled metrics (Crucible v0.2.7+).\n * Use for metrics like current connections, memory usage, temperature, etc.\n */\nexport class Gauge {\n private value = 0;\n private labeledValues = new Map<string, number>();\n\n constructor(public readonly name: MetricName) {}\n\n /**\n * Set gauge to specific value\n *\n * @param value - New gauge value (can be any number, including negative)\n * @param labels - Optional label dimensions for this observation\n *\n * @example\n * ```typescript\n * gauge.set(42); // Set unlabeled to 42\n * gauge.set(-10); // Negative values allowed\n * gauge.set(1, { phase: 'collect' }); // Set labeled instance\n * ```\n */\n set(value: number, labels?: Record<string, string>): void {\n if (labels && Object.keys(labels).length > 0) {\n const labelKey = this.serializeLabels(labels);\n this.labeledValues.set(labelKey, value);\n } else {\n this.value = value;\n }\n }\n\n /**\n * Increment gauge by delta (default: 1)\n *\n * @param delta - Amount to increment (can be negative)\n * @param labels - Optional label dimensions for this observation\n */\n inc(delta = 1, labels?: Record<string, string>): void {\n if (labels && Object.keys(labels).length > 0) {\n const labelKey = this.serializeLabels(labels);\n const current = this.labeledValues.get(labelKey) || 0;\n this.labeledValues.set(labelKey, current + delta);\n } else {\n this.value += delta;\n }\n }\n\n /**\n * Decrement gauge by delta (default: 1)\n *\n * @param delta - Amount to decrement (can be negative)\n * @param labels - Optional label dimensions for this observation\n */\n dec(delta = 1, labels?: Record<string, string>): void {\n if (labels && Object.keys(labels).length > 0) {\n const labelKey = this.serializeLabels(labels);\n const current = this.labeledValues.get(labelKey) || 0;\n this.labeledValues.set(labelKey, current - delta);\n } else {\n this.value -= delta;\n }\n }\n\n /**\n * Get current gauge value (unlabeled)\n */\n getValue(): number {\n return this.value;\n }\n\n /**\n * Get all labeled values\n * @returns Map of serialized label keys to values\n */\n getLabeledValues(): Map<string, number> {\n return new Map(this.labeledValues);\n }\n\n /**\n * Get value for specific label combination\n */\n getValueForLabels(labels: Record<string, string>): number {\n const labelKey = this.serializeLabels(labels);\n return this.labeledValues.get(labelKey) || 0;\n }\n\n /**\n * Reset gauge to zero (all label combinations)\n */\n reset(): void {\n this.value = 0;\n this.labeledValues.clear();\n }\n\n /**\n * Serialize labels to deterministic string key\n * Format: key1=value1,key2=value2 (sorted by key)\n */\n private serializeLabels(labels: Record<string, string>): string {\n return Object.entries(labels)\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([k, v]) => `${k}=${v}`)\n .join(\",\");\n }\n}\n","/**\n * Taxonomy loader for metrics definitions\n *\n * Loads and caches metrics taxonomy from config/crucible-ts/taxonomy/metrics.yaml\n * Provides default histogram buckets per ADR-0007\n */\n\nimport { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { parse as parseYaml } from \"yaml\";\nimport type { MetricName, MetricUnit } from \"./types.js\";\n\n/**\n * Metric definition from taxonomy\n */\nexport interface MetricDefinition {\n name: MetricName;\n unit: MetricUnit;\n description: string;\n}\n\n/**\n * Taxonomy structure\n */\nexport interface MetricsTaxonomy {\n version: string;\n defaults: {\n histogram_buckets: {\n ms_metrics: number[];\n };\n };\n metrics: MetricDefinition[];\n}\n\n/**\n * Default histogram buckets for _ms metrics (ADR-0007)\n * [1, 5, 10, 50, 100, 500, 1000, 5000, 10000] milliseconds\n */\nexport const DEFAULT_MS_BUCKETS = [1, 5, 10, 50, 100, 500, 1000, 5000, 10000];\n\n/**\n * Singleton taxonomy loader\n */\nclass TaxonomyLoader {\n private static instance: TaxonomyLoader;\n private taxonomy: MetricsTaxonomy | null = null;\n private loadPromise: Promise<MetricsTaxonomy> | null = null;\n private loadError: Error | null = null;\n\n private constructor() {\n // Private constructor for singleton\n }\n\n /**\n * Get singleton instance\n */\n static getInstance(): TaxonomyLoader {\n if (!TaxonomyLoader.instance) {\n TaxonomyLoader.instance = new TaxonomyLoader();\n }\n return TaxonomyLoader.instance;\n }\n\n /**\n * Load taxonomy from YAML file\n */\n private async load(): Promise<MetricsTaxonomy> {\n if (this.taxonomy !== null) {\n return this.taxonomy;\n }\n\n if (this.loadError !== null) {\n throw this.loadError;\n }\n\n if (this.loadPromise) {\n return this.loadPromise;\n }\n\n this.loadPromise = (async () => {\n try {\n // Resolve path to taxonomy file\n // From src/telemetry/ → ../../config/crucible-ts/taxonomy/metrics.yaml\n const taxonomyPath = join(\n __dirname,\n \"..\",\n \"..\",\n \"config\",\n \"crucible-ts\",\n \"taxonomy\",\n \"metrics.yaml\",\n );\n\n const content = await readFile(taxonomyPath, \"utf-8\");\n this.taxonomy = parseYaml(content) as MetricsTaxonomy;\n\n return this.taxonomy;\n } catch (err) {\n this.loadError = err instanceof Error ? err : new Error(String(err));\n throw new Error(`Failed to load metrics taxonomy: ${this.loadError.message}`);\n }\n })();\n\n return this.loadPromise;\n }\n\n /**\n * Get taxonomy (async)\n */\n async getTaxonomy(): Promise<MetricsTaxonomy> {\n return this.load();\n }\n\n /**\n * Get metric definition by name\n */\n async getMetric(name: MetricName): Promise<MetricDefinition | undefined> {\n const taxonomy = await this.load();\n return taxonomy.metrics.find((m) => m.name === name);\n }\n\n /**\n * Get default unit for metric\n */\n async getDefaultUnit(name: MetricName): Promise<MetricUnit | undefined> {\n const metric = await this.getMetric(name);\n return metric?.unit;\n }\n\n /**\n * Get default histogram buckets for metric\n * Returns ADR-0007 buckets for _ms metrics, undefined for others\n */\n async getDefaultBuckets(name: MetricName): Promise<number[] | undefined> {\n // Check if metric name ends with _ms\n if (name.endsWith(\"_ms\")) {\n const taxonomy = await this.load();\n return taxonomy.defaults.histogram_buckets.ms_metrics;\n }\n return undefined;\n }\n\n /**\n * Check if metric name is valid (exists in taxonomy)\n */\n async isValidMetricName(name: string): Promise<boolean> {\n try {\n const taxonomy = await this.load();\n return taxonomy.metrics.some((m) => m.name === name);\n } catch {\n return false;\n }\n }\n\n /**\n * Reset loader state (for testing)\n * @internal\n */\n static _reset(): void {\n TaxonomyLoader.instance = new TaxonomyLoader();\n }\n}\n\n/**\n * Get metrics taxonomy\n *\n * @returns Promise resolving to taxonomy\n */\nexport async function getTaxonomy(): Promise<MetricsTaxonomy> {\n return TaxonomyLoader.getInstance().getTaxonomy();\n}\n\n/**\n * Get metric definition by name\n *\n * @param name - Metric name\n * @returns Promise resolving to metric definition or undefined\n */\nexport async function getMetric(name: MetricName): Promise<MetricDefinition | undefined> {\n return TaxonomyLoader.getInstance().getMetric(name);\n}\n\n/**\n * Get default unit for metric from taxonomy\n *\n * @param name - Metric name\n * @returns Promise resolving to unit or undefined\n */\nexport async function getDefaultUnit(name: MetricName): Promise<MetricUnit | undefined> {\n return TaxonomyLoader.getInstance().getDefaultUnit(name);\n}\n\n/**\n * Get default histogram buckets for metric\n *\n * Returns ADR-0007 buckets ([1, 5, 10, 50, 100, 500, 1000, 5000, 10000]) for\n * metrics ending with _ms, undefined for others.\n *\n * @param name - Metric name\n * @returns Promise resolving to bucket array or undefined\n *\n * @example\n * ```typescript\n * const buckets = await getDefaultBuckets('config_load_ms');\n * // Returns [1, 5, 10, 50, 100, 500, 1000, 5000, 10000]\n * ```\n */\nexport async function getDefaultBuckets(name: MetricName): Promise<number[] | undefined> {\n return TaxonomyLoader.getInstance().getDefaultBuckets(name);\n}\n\n/**\n * Check if metric name is valid (exists in taxonomy)\n *\n * @param name - Metric name to check\n * @returns Promise resolving to true if valid\n */\nexport async function isValidMetricName(name: string): Promise<boolean> {\n return TaxonomyLoader.getInstance().isValidMetricName(name);\n}\n\n// Export for testing\nexport { TaxonomyLoader };\n","/**\n * Histogram metric implementation\n *\n * Histogram with OTLP-compatible cumulative buckets, auto-applying ADR-0007\n * default buckets for _ms metrics.\n */\n\nimport { DEFAULT_MS_BUCKETS } from \"./taxonomy.js\";\nimport type { HistogramBucket, HistogramOptions, HistogramSummary, MetricName } from \"./types.js\";\n\n/**\n * Labeled histogram state\n */\ninterface LabeledHistogramState {\n count: number;\n sum: number;\n bucketCounts: Map<number, number>;\n}\n\n/**\n * Histogram metric\n *\n * Tracks distribution of values using cumulative buckets (OTLP-compatible).\n * Automatically applies ADR-0007 default buckets for _ms metrics.\n * Supports labeled metrics (Crucible v0.2.7+).\n */\nexport class Histogram {\n private count = 0;\n private sum = 0;\n private bucketCounts: Map<number, number> = new Map();\n private labeledStates = new Map<string, LabeledHistogramState>();\n private readonly buckets: number[];\n\n constructor(\n public readonly name: MetricName,\n options?: HistogramOptions,\n ) {\n // Determine buckets: custom > ADR-0007 defaults for _ms metrics > empty\n if (options?.buckets) {\n this.buckets = [...options.buckets].sort((a, b) => a - b);\n } else if (name.endsWith(\"_ms\") || name.endsWith(\"_seconds\")) {\n this.buckets = [...DEFAULT_MS_BUCKETS];\n } else {\n this.buckets = [];\n }\n\n // Initialize bucket counts\n for (const bucket of this.buckets) {\n this.bucketCounts.set(bucket, 0);\n }\n }\n\n /**\n * Record an observation\n *\n * @param value - Value to observe (typically a duration in ms or seconds)\n * @param labels - Optional label dimensions for this observation\n *\n * @example\n * ```typescript\n * const start = performance.now();\n * // ... operation ...\n * histogram.observe(performance.now() - start);\n * histogram.observe(duration, { phase: 'collect', result: 'success' });\n * ```\n */\n observe(value: number, labels?: Record<string, string>): void {\n if (labels && Object.keys(labels).length > 0) {\n // Labeled observation\n const labelKey = this.serializeLabels(labels);\n let state = this.labeledStates.get(labelKey);\n\n if (!state) {\n // Initialize new labeled state\n state = {\n count: 0,\n sum: 0,\n bucketCounts: new Map(),\n };\n for (const bucket of this.buckets) {\n state.bucketCounts.set(bucket, 0);\n }\n this.labeledStates.set(labelKey, state);\n }\n\n state.count++;\n state.sum += value;\n\n // Update cumulative bucket counts\n for (const bucket of this.buckets) {\n if (value <= bucket) {\n state.bucketCounts.set(bucket, (state.bucketCounts.get(bucket) || 0) + 1);\n }\n }\n } else {\n // Unlabeled observation\n this.count++;\n this.sum += value;\n\n // Update cumulative bucket counts\n for (const bucket of this.buckets) {\n if (value <= bucket) {\n this.bucketCounts.set(bucket, (this.bucketCounts.get(bucket) || 0) + 1);\n }\n }\n }\n }\n\n /**\n * Get histogram summary\n *\n * Returns OTLP-compatible histogram summary with cumulative bucket counts.\n */\n getSummary(): HistogramSummary {\n const buckets: HistogramBucket[] = this.buckets.map((le) => ({\n le,\n count: this.bucketCounts.get(le) || 0,\n }));\n\n return {\n count: this.count,\n sum: this.sum,\n buckets,\n };\n }\n\n /**\n * Get current observation count\n */\n getCount(): number {\n return this.count;\n }\n\n /**\n * Get sum of all observed values\n */\n getSum(): number {\n return this.sum;\n }\n\n /**\n * Get average of observed values\n */\n getAverage(): number {\n return this.count > 0 ? this.sum / this.count : 0;\n }\n\n /**\n * Get all labeled summaries\n * @returns Map of serialized label keys to histogram summaries\n */\n getLabeledSummaries(): Map<string, HistogramSummary> {\n const summaries = new Map<string, HistogramSummary>();\n\n for (const [labelKey, state] of this.labeledStates) {\n const buckets: HistogramBucket[] = this.buckets.map((le) => ({\n le,\n count: state.bucketCounts.get(le) || 0,\n }));\n\n summaries.set(labelKey, {\n count: state.count,\n sum: state.sum,\n buckets,\n });\n }\n\n return summaries;\n }\n\n /**\n * Get summary for specific label combination\n */\n getSummaryForLabels(labels: Record<string, string>): HistogramSummary | null {\n const labelKey = this.serializeLabels(labels);\n const state = this.labeledStates.get(labelKey);\n\n if (!state) {\n return null;\n }\n\n const buckets: HistogramBucket[] = this.buckets.map((le) => ({\n le,\n count: state.bucketCounts.get(le) || 0,\n }));\n\n return {\n count: state.count,\n sum: state.sum,\n buckets,\n };\n }\n\n /**\n * Reset histogram to initial state (all label combinations)\n */\n reset(): void {\n this.count = 0;\n this.sum = 0;\n for (const bucket of this.buckets) {\n this.bucketCounts.set(bucket, 0);\n }\n this.labeledStates.clear();\n }\n\n /**\n * Serialize labels to deterministic string key\n * Format: key1=value1,key2=value2 (sorted by key)\n */\n private serializeLabels(labels: Record<string, string>): string {\n return Object.entries(labels)\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([k, v]) => `${k}=${v}`)\n .join(\",\");\n }\n}\n","/**\n * Metrics registry - central registry for all metrics\n *\n * Provides singleton registry for counters, gauges, and histograms.\n * Exports events in schema-compliant format.\n */\n\nimport { Counter } from \"./counter.js\";\nimport { Gauge } from \"./gauge.js\";\nimport { Histogram } from \"./histogram.js\";\nimport { getDefaultUnit } from \"./taxonomy.js\";\nimport type { FlushOptions, HistogramOptions, MetricName, MetricsEvent } from \"./types.js\";\n\n/**\n * Metrics registry\n *\n * Central registry for all metrics. Provides factory methods for counters,\n * gauges, and histograms. Exports metrics as schema-compliant events.\n */\nexport class MetricsRegistry {\n private counters: Map<MetricName, Counter> = new Map();\n private gauges: Map<MetricName, Gauge> = new Map();\n private histograms: Map<MetricName, Histogram> = new Map();\n\n /**\n * Get or create a counter\n *\n * @param name - Metric name from taxonomy\n * @returns Counter instance\n *\n * @example\n * ```typescript\n * const counter = registry.counter('schema_validations');\n * counter.inc();\n * ```\n */\n counter(name: MetricName): Counter {\n let counter = this.counters.get(name);\n if (!counter) {\n counter = new Counter(name);\n this.counters.set(name, counter);\n }\n return counter;\n }\n\n /**\n * Get or create a gauge\n *\n * @param name - Metric name from taxonomy\n * @returns Gauge instance\n *\n * @example\n * ```typescript\n * const gauge = registry.gauge('foundry_lookup_count');\n * gauge.set(42);\n * ```\n */\n gauge(name: MetricName): Gauge {\n let gauge = this.gauges.get(name);\n if (!gauge) {\n gauge = new Gauge(name);\n this.gauges.set(name, gauge);\n }\n return gauge;\n }\n\n /**\n * Get or create a histogram\n *\n * @param name - Metric name from taxonomy\n * @param options - Optional histogram options\n * @returns Histogram instance\n *\n * @example\n * ```typescript\n * // Auto-applies ADR-0007 buckets for _ms metrics\n * const histogram = registry.histogram('config_load_ms');\n * histogram.observe(42.5);\n *\n * // Custom buckets\n * const custom = registry.histogram('custom_metric', {\n * buckets: [10, 50, 100, 500, 1000]\n * });\n * ```\n */\n histogram(name: MetricName, options?: HistogramOptions): Histogram {\n let histogram = this.histograms.get(name);\n if (!histogram) {\n histogram = new Histogram(name, options);\n this.histograms.set(name, histogram);\n }\n return histogram;\n }\n\n /**\n * Export all metrics as events\n *\n * Returns array of schema-compliant MetricsEvent objects.\n * Does not clear metrics (use flush() to clear after export).\n *\n * @returns Promise resolving to array of metrics events\n *\n * @example\n * ```typescript\n * const events = await registry.export();\n * console.log(JSON.stringify(events, null, 2));\n * ```\n */\n async export(): Promise<MetricsEvent[]> {\n const events: MetricsEvent[] = [];\n const timestamp = new Date().toISOString();\n\n // Export counters (unlabeled + labeled) - Crucible v0.2.7+\n for (const [name, counter] of this.counters) {\n const unit = await getDefaultUnit(name);\n\n // Always export unlabeled value (for backwards compatibility)\n events.push({\n timestamp,\n name,\n value: counter.getValue(),\n unit,\n });\n\n // Export labeled values (only if > 0)\n for (const [labelKey, value] of counter.getLabeledValues()) {\n if (value > 0) {\n const tags = this.deserializeLabels(labelKey);\n events.push({\n timestamp,\n name,\n value,\n tags,\n unit,\n });\n }\n }\n }\n\n // Export gauges (unlabeled + labeled) - Crucible v0.2.7+\n for (const [name, gauge] of this.gauges) {\n const unit = await getDefaultUnit(name);\n\n // Export unlabeled value (always export gauges, even if zero)\n events.push({\n timestamp,\n name,\n value: gauge.getValue(),\n unit,\n });\n\n // Export labeled values\n for (const [labelKey, value] of gauge.getLabeledValues()) {\n const tags = this.deserializeLabels(labelKey);\n events.push({\n timestamp,\n name,\n value,\n tags,\n unit,\n });\n }\n }\n\n // Export histograms (unlabeled + labeled) - Crucible v0.2.7+\n for (const [name, histogram] of this.histograms) {\n const unit = await getDefaultUnit(name);\n\n // Always export unlabeled summary (for backwards compatibility)\n events.push({\n timestamp,\n name,\n value: histogram.getSummary(),\n unit,\n });\n\n // Export labeled summaries (only if count > 0)\n for (const [labelKey, summary] of histogram.getLabeledSummaries()) {\n if (summary.count > 0) {\n const tags = this.deserializeLabels(labelKey);\n events.push({\n timestamp,\n name,\n value: summary,\n tags,\n unit,\n });\n }\n }\n }\n\n return events;\n }\n\n /**\n * Deserialize label key back to tags object\n * Format: key1=value1,key2=value2 → {key1: \"value1\", key2: \"value2\"}\n */\n private deserializeLabels(labelKey: string): Record<string, string> {\n if (!labelKey) {\n return {};\n }\n\n const tags: Record<string, string> = {};\n for (const pair of labelKey.split(\",\")) {\n const [key, value] = pair.split(\"=\");\n if (key && value) {\n tags[key] = value;\n }\n }\n return tags;\n }\n\n /**\n * Export and clear all metrics\n *\n * Exports metrics as events, optionally emits them via logger,\n * then resets all metrics to zero.\n *\n * @param options - Flush options\n * @returns Promise resolving to array of exported events\n *\n * @example\n * ```typescript\n * // Export and clear\n * const events = await registry.flush();\n *\n * // Export, emit to logger, and clear\n * const events = await registry.flush({\n * emit: (events) => console.log(JSON.stringify(events))\n * });\n * ```\n */\n async flush(options?: FlushOptions): Promise<MetricsEvent[]> {\n const events = await this.export();\n\n try {\n // Emit if logger provided\n if (options?.emit) {\n options.emit(events);\n }\n } finally {\n // Always clear metrics, even if emit throws\n this.clear();\n }\n\n return events;\n }\n\n /**\n * Clear all metrics (reset to zero)\n *\n * Resets all counters, gauges, and histograms to their initial state.\n */\n clear(): void {\n for (const counter of this.counters.values()) {\n counter.reset();\n }\n for (const gauge of this.gauges.values()) {\n gauge.reset();\n }\n for (const histogram of this.histograms.values()) {\n histogram.reset();\n }\n }\n\n /**\n * Get all registered metric names\n *\n * Returns array of all metric names that have been accessed\n * (counters, gauges, or histograms).\n */\n getMetricNames(): MetricName[] {\n const names = new Set<MetricName>();\n for (const name of this.counters.keys()) {\n names.add(name);\n }\n for (const name of this.gauges.keys()) {\n names.add(name);\n }\n for (const name of this.histograms.keys()) {\n names.add(name);\n }\n return Array.from(names);\n }\n\n /**\n * Get total count of registered metrics\n */\n getMetricCount(): number {\n return this.counters.size + this.gauges.size + this.histograms.size;\n }\n}\n","/**\n * Telemetry types - TypeScript types for metrics events\n *\n * Based on schemas/crucible-ts/observability/metrics/v1.0.0/metrics-event.schema.json\n * and config/crucible-ts/taxonomy/metrics.yaml\n */\n\n/**\n * Metric name from taxonomy\n * Aligned with config/crucible-ts/taxonomy/metrics.yaml#/$defs/metricName\n * Updated for Crucible v0.2.18 (HTTP server metrics)\n */\nexport type MetricName =\n // Core module metrics\n | \"schema_validations\"\n | \"schema_validation_errors\"\n | \"config_load_ms\"\n | \"config_load_errors\"\n | \"pathfinder_find_ms\"\n | \"pathfinder_validation_errors\"\n | \"pathfinder_security_warnings\"\n | \"foundry_lookup_count\"\n | \"logging_emit_count\"\n | \"logging_emit_latency_ms\"\n | \"goneat_command_duration_ms\"\n // Prometheus exporter metrics\n | \"prometheus_exporter_refresh_duration_seconds\"\n | \"prometheus_exporter_refresh_total\"\n | \"prometheus_exporter_refresh_errors_total\"\n | \"prometheus_exporter_refresh_inflight\"\n | \"prometheus_exporter_http_requests_total\"\n | \"prometheus_exporter_http_errors_total\"\n | \"prometheus_exporter_restarts_total\"\n // Foundry MIME detection metrics\n | \"foundry_mime_detections_total_json\"\n | \"foundry_mime_detections_total_xml\"\n | \"foundry_mime_detections_total_yaml\"\n | \"foundry_mime_detections_total_csv\"\n | \"foundry_mime_detections_total_plain_text\"\n | \"foundry_mime_detections_total_unknown\"\n | \"foundry_mime_detection_ms_json\"\n | \"foundry_mime_detection_ms_xml\"\n | \"foundry_mime_detection_ms_yaml\"\n | \"foundry_mime_detection_ms_csv\"\n | \"foundry_mime_detection_ms_plain_text\"\n | \"foundry_mime_detection_ms_unknown\"\n // Error handling metrics\n | \"error_handling_wraps_total\"\n | \"error_handling_wrap_ms\"\n // FulHash metrics\n | \"fulhash_operations_total_xxh3_128\"\n | \"fulhash_operations_total_sha256\"\n | \"fulhash_hash_string_total\"\n | \"fulhash_bytes_hashed_total\"\n | \"fulhash_operation_ms\"\n // HTTP server metrics (v0.2.18)\n | \"http_requests_total\"\n | \"http_request_duration_seconds\"\n | \"http_request_size_bytes\"\n | \"http_response_size_bytes\"\n | \"http_active_requests\";\n\n/**\n * Metric unit from taxonomy\n * Aligned with config/crucible-ts/taxonomy/metrics.yaml#/$defs/metricUnit\n * Updated for Crucible v0.2.7 (adds 's' for seconds)\n */\nexport type MetricUnit = \"count\" | \"ms\" | \"bytes\" | \"percent\" | \"s\";\n\n/**\n * Histogram bucket for OTLP-compatible histograms\n */\nexport interface HistogramBucket {\n /** Upper bound (less-than-or-equal) for the bucket */\n le: number;\n /** Cumulative count up to and including this bucket */\n count: number;\n}\n\n/**\n * Histogram summary payload\n */\nexport interface HistogramSummary {\n /** Total count of observations */\n count: number;\n /** Sum of all observed values */\n sum: number;\n /** Ordered buckets with cumulative counts (OTLP-compatible) */\n buckets: HistogramBucket[];\n}\n\n/**\n * Metric value (scalar or histogram)\n */\nexport type MetricValue = number | HistogramSummary;\n\n/**\n * Metrics event structure\n * Aligned with schemas/crucible-ts/observability/metrics/v1.0.0/metrics-event.schema.json\n */\nexport interface MetricsEvent {\n /** RFC3339 timestamp of metric emission */\n timestamp: string;\n /** Metric identifier from taxonomy */\n name: MetricName;\n /** Measurement payload (scalar or histogram summary) */\n value: MetricValue;\n /** Optional key/value dimensions */\n tags?: Record<string, string>;\n /** Optional metric unit (defaults to taxonomy default) */\n unit?: MetricUnit;\n}\n\n/**\n * Histogram options for customization\n */\nexport interface HistogramOptions {\n /** Custom bucket boundaries (overrides default ADR-0007 buckets) */\n buckets?: number[];\n}\n\n/**\n * Flush options for metrics registry\n */\nexport interface FlushOptions {\n /** Optional logger function to emit metrics */\n emit?: (events: MetricsEvent[]) => void;\n}\n\n/**\n * Type guard to check if value is a histogram summary\n */\nexport function isHistogramSummary(value: unknown): value is HistogramSummary {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"count\" in value &&\n \"sum\" in value &&\n \"buckets\" in value\n );\n}\n\n/**\n * Type guard to check if metric name is valid\n * Aligned with Crucible v0.2.18 taxonomy\n */\nexport function isValidMetricName(name: string): name is MetricName {\n const validNames: MetricName[] = [\n // Core module metrics\n \"schema_validations\",\n \"schema_validation_errors\",\n \"config_load_ms\",\n \"config_load_errors\",\n \"pathfinder_find_ms\",\n \"pathfinder_validation_errors\",\n \"pathfinder_security_warnings\",\n \"foundry_lookup_count\",\n \"logging_emit_count\",\n \"logging_emit_latency_ms\",\n \"goneat_command_duration_ms\",\n // Prometheus exporter metrics\n \"prometheus_exporter_refresh_duration_seconds\",\n \"prometheus_exporter_refresh_total\",\n \"prometheus_exporter_refresh_errors_total\",\n \"prometheus_exporter_refresh_inflight\",\n \"prometheus_exporter_http_requests_total\",\n \"prometheus_exporter_http_errors_total\",\n \"prometheus_exporter_restarts_total\",\n // Foundry MIME detection metrics\n \"foundry_mime_detections_total_json\",\n \"foundry_mime_detections_total_xml\",\n \"foundry_mime_detections_total_yaml\",\n \"foundry_mime_detections_total_csv\",\n \"foundry_mime_detections_total_plain_text\",\n \"foundry_mime_detections_total_unknown\",\n \"foundry_mime_detection_ms_json\",\n \"foundry_mime_detection_ms_xml\",\n \"foundry_mime_detection_ms_yaml\",\n \"foundry_mime_detection_ms_csv\",\n \"foundry_mime_detection_ms_plain_text\",\n \"foundry_mime_detection_ms_unknown\",\n // Error handling metrics\n \"error_handling_wraps_total\",\n \"error_handling_wrap_ms\",\n // FulHash metrics\n \"fulhash_operations_total_xxh3_128\",\n \"fulhash_operations_total_sha256\",\n \"fulhash_hash_string_total\",\n \"fulhash_bytes_hashed_total\",\n \"fulhash_operation_ms\",\n // HTTP server metrics\n \"http_requests_total\",\n \"http_request_duration_seconds\",\n \"http_request_size_bytes\",\n \"http_response_size_bytes\",\n \"http_active_requests\",\n ];\n return validNames.includes(name as MetricName);\n}\n\n/**\n * Type guard to check if unit is valid\n */\nexport function isValidMetricUnit(unit: string): unit is MetricUnit {\n const validUnits: MetricUnit[] = [\"count\", \"ms\", \"bytes\", \"percent\", \"s\"];\n return validUnits.includes(unit as MetricUnit);\n}\n","/**\n * Metrics event validators\n *\n * Schema validation for metrics events using existing src/schema infrastructure\n */\n\nimport { compileSchemaById } from \"../schema/index.js\";\nimport type { CompiledValidator } from \"../schema/types.js\";\n\n/**\n * Singleton validator for metrics events\n *\n * Pre-compiles the metrics-event schema at first access for optimal performance.\n * Reuses existing AJV setup from src/schema module.\n */\nclass MetricsValidator {\n private static instance: MetricsValidator;\n private validateFn: CompiledValidator | null = null;\n private initPromise: Promise<void> | null = null;\n private initError: Error | null = null;\n\n private constructor() {\n // Private constructor for singleton\n }\n\n /**\n * Get singleton instance\n */\n static getInstance(): MetricsValidator {\n if (!MetricsValidator.instance) {\n MetricsValidator.instance = new MetricsValidator();\n }\n return MetricsValidator.instance;\n }\n\n /**\n * Initialize validator (lazy load, async)\n */\n private async init(): Promise<void> {\n if (this.validateFn !== null || this.initError !== null) {\n return; // Already initialized\n }\n\n if (this.initPromise) {\n return this.initPromise; // Already initializing\n }\n\n this.initPromise = (async () => {\n try {\n // Compile schema using existing schema infrastructure\n this.validateFn = await compileSchemaById(\"observability/metrics/v1.0.0/metrics-event\");\n } catch (err) {\n this.initError = err instanceof Error ? err : new Error(String(err));\n throw new Error(`Failed to initialize metrics validator: ${this.initError.message}`);\n }\n })();\n\n return this.initPromise;\n }\n\n /**\n * Validate metrics event against schema\n *\n * @param event - Metrics event to validate\n * @returns Promise resolving to true if valid, false otherwise\n */\n async validate(event: unknown): Promise<boolean> {\n if (this.validateFn === null) {\n await this.init();\n }\n\n if (this.initError) {\n throw this.initError;\n }\n\n if (!this.validateFn) {\n throw new Error(\"Validator not initialized\");\n }\n\n return this.validateFn(event);\n }\n\n /**\n * Get validation errors from last validation\n */\n getErrors() {\n if (!this.validateFn) {\n return null;\n }\n return this.validateFn.errors;\n }\n\n /**\n * Reset validator state (for testing)\n * @internal\n */\n static _reset(): void {\n MetricsValidator.instance = new MetricsValidator();\n }\n}\n\n/**\n * Validate metrics event against schema\n *\n * Uses pre-compiled validator singleton for optimal performance.\n *\n * @param event - Metrics event to validate\n * @returns Promise resolving to true if valid\n *\n * @example\n * ```typescript\n * const event: MetricsEvent = {\n * timestamp: new Date().toISOString(),\n * name: 'schema_validations',\n * value: 42\n * };\n *\n * if (await validateMetricsEvent(event)) {\n * // Event is schema-compliant\n * } else {\n * const errors = getValidationErrors();\n * console.error('Validation failed:', errors);\n * }\n * ```\n */\nexport async function validateMetricsEvent(event: unknown): Promise<boolean> {\n return MetricsValidator.getInstance().validate(event);\n}\n\n/**\n * Validate array of metrics events\n *\n * @param events - Array of metrics events\n * @returns Promise resolving to true if all valid\n */\nexport async function validateMetricsEvents(events: unknown[]): Promise<boolean> {\n for (const event of events) {\n if (!(await validateMetricsEvent(event))) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * Get validation errors from last validation\n */\nexport function getValidationErrors() {\n return MetricsValidator.getInstance().getErrors();\n}\n\n/**\n * Format validation errors as human-readable string\n */\nexport function formatValidationErrors(\n errors: Array<{ instancePath?: string; message?: string }>,\n): string {\n return errors\n .map((err) => {\n const path = err.instancePath || \"(root)\";\n const message = err.message || \"validation failed\";\n return `${path}: ${message}`;\n })\n .join(\"; \");\n}\n\n/**\n * Assert that metrics event is valid (throws if not)\n *\n * @param event - Metrics event to validate\n * @throws {Error} If validation fails\n */\nexport async function assertValidMetricsEvent(event: unknown): Promise<void> {\n if (!(await validateMetricsEvent(event))) {\n const errors = getValidationErrors();\n const message = errors ? formatValidationErrors(errors) : \"Metrics event validation failed\";\n throw new Error(`Invalid metrics event: ${message}`);\n }\n}\n\n// Export for testing\nexport { MetricsValidator };\n","/**\n * Telemetry module - metrics collection and export\n *\n * Provides counter, gauge, and histogram metrics with schema validation\n * and taxonomy-based defaults (ADR-0007).\n */\n\nexport const VERSION = \"1.0.0\";\n\n// Core registry and singleton\nexport { MetricsRegistry } from \"./registry.js\";\n\nimport { MetricsRegistry } from \"./registry.js\";\n\n/**\n * Default singleton metrics registry\n *\n * Use this for application-wide metrics collection.\n *\n * @example\n * ```typescript\n * import { metrics } from '@fulmenhq/tsfulmen/telemetry';\n *\n * // Increment counter\n * metrics.counter('schema_validations').inc();\n *\n * // Record histogram observation\n * metrics.histogram('config_load_ms').observe(42.5);\n *\n * // Export all metrics\n * const events = await metrics.export();\n * ```\n */\nexport const metrics = new MetricsRegistry();\n\n// Metric types\nexport { Counter } from \"./counter.js\";\nexport { Gauge } from \"./gauge.js\";\nexport { Histogram } from \"./histogram.js\";\n// Taxonomy\nexport type { MetricDefinition, MetricsTaxonomy } from \"./taxonomy.js\";\nexport {\n DEFAULT_MS_BUCKETS,\n getDefaultBuckets,\n getDefaultUnit,\n getMetric,\n getTaxonomy,\n isValidMetricName as isValidMetricNameTaxonomy,\n} from \"./taxonomy.js\";\n// Types\nexport type {\n FlushOptions,\n HistogramBucket,\n HistogramOptions,\n HistogramSummary,\n MetricName,\n MetricsEvent,\n MetricUnit,\n MetricValue,\n} from \"./types.js\";\nexport {\n isHistogramSummary,\n isValidMetricName,\n isValidMetricUnit,\n} from \"./types.js\";\n\n// Validators\nexport {\n assertValidMetricsEvent,\n formatValidationErrors,\n getValidationErrors,\n validateMetricsEvent,\n validateMetricsEvents,\n} from \"./validators.js\";\n","/**\n * Schema validator - implements AJV-based schema validation with goneat integration\n */\n\nimport { readFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { AnySchema } from \"ajv\";\nimport Ajv from \"ajv\";\nimport Ajv2019 from \"ajv/dist/2019.js\";\nimport Ajv2020 from \"ajv/dist/2020.js\";\nimport AjvDraft04 from \"ajv-draft-04\";\nimport { parse as parseYAML } from \"yaml\";\nimport { metrics } from \"../telemetry/index.js\";\nimport { applyFulmenAjvFormats } from \"./ajv-formats.js\";\nimport { SchemaValidationError } from \"./errors.js\";\nimport { getSchemaRegistry } from \"./registry.js\";\nimport type {\n CompiledValidator,\n SchemaInput,\n SchemaRegistryOptions,\n SchemaValidationResult,\n} from \"./types.js\";\nimport { createDiagnostic } from \"./utils.js\";\n\n/**\n * Supported JSON Schema dialects for meta validation + compilation.\n */\ntype JsonSchemaDialect = \"draft-04\" | \"draft-06\" | \"draft-07\" | \"draft-2019-09\" | \"draft-2020-12\";\n\n/**\n * AJV instances by dialect\n */\nconst ajvInstances = new Map<JsonSchemaDialect, Ajv>();\n\n/**\n * Metaschema initialization promises by dialect\n */\nconst metaschemaReady = new Map<JsonSchemaDialect, Promise<void>>();\n\n/**\n * Schema cache for compiled validators\n */\nconst schemaCache = new Map<string, CompiledValidator>();\n\n/**\n * Load metaschema from Crucible SSOT\n */\nasync function loadMetaSchema(draft: JsonSchemaDialect): Promise<Record<string, unknown>> {\n const __filename = fileURLToPath(import.meta.url);\n const __dirname = dirname(__filename);\n const metaSchemaPath = join(\n __dirname,\n \"..\",\n \"..\",\n \"schemas\",\n \"crucible-ts\",\n \"meta\",\n draft,\n \"schema.json\",\n );\n\n const content = await readFile(metaSchemaPath, \"utf-8\");\n return JSON.parse(content) as Record<string, unknown>;\n}\n\n/**\n * Load vocabulary schemas (draft 2019-09 / 2020-12)\n */\nasync function loadVocabularySchemas(draft: JsonSchemaDialect): Promise<Record<string, unknown>[]> {\n if (draft !== \"draft-2019-09\" && draft !== \"draft-2020-12\") {\n return [];\n }\n\n const __filename = fileURLToPath(import.meta.url);\n const __dirname = dirname(__filename);\n const vocabDir = join(__dirname, \"..\", \"..\", \"schemas\", \"crucible-ts\", \"meta\", draft, \"meta\");\n\n const vocabFiles =\n draft === \"draft-2020-12\"\n ? [\n \"core.json\",\n \"applicator.json\",\n \"unevaluated.json\",\n \"validation.json\",\n \"meta-data.json\",\n \"format-annotation.json\",\n \"content.json\",\n ]\n : [\n \"core.json\",\n \"applicator.json\",\n \"validation.json\",\n \"meta-data.json\",\n \"format.json\",\n \"content.json\",\n ];\n\n const schemas: Record<string, unknown>[] = [];\n for (const file of vocabFiles) {\n try {\n const content = await readFile(join(vocabDir, file), \"utf-8\");\n schemas.push(JSON.parse(content) as Record<string, unknown>);\n } catch {\n // Vocabulary schema not found, skip\n }\n }\n\n return schemas;\n}\n\n/**\n * Load referenced schemas (including YAML files) for AJV\n *\n * Resolves relative paths from schemas/ and config/ directories.\n * Handles both relative paths and https://schemas.fulmenhq.dev URIs.\n *\n * Per Canonical URI Resolution Standard (v0.4.2+), crucible-hosted schemas use:\n * https://schemas.fulmenhq.dev/crucible/<topic>/<version>/<filename>\n *\n * We only embed crucible schemas locally. Other modules (goneat/, enact/, etc.)\n * are not embedded and cannot be resolved offline.\n */\nasync function loadReferencedSchema(uri: string): Promise<Record<string, unknown>> {\n const __filename = fileURLToPath(import.meta.url);\n const __dirname = dirname(__filename);\n const repoRoot = join(__dirname, \"..\", \"..\");\n\n let resolvedPath: string;\n\n // Handle https://schemas.fulmenhq.dev/ URIs - map to local files\n if (uri.startsWith(\"https://schemas.fulmenhq.dev/\")) {\n let relativePath = uri.replace(\"https://schemas.fulmenhq.dev/\", \"\");\n\n // Strip crucible/ module prefix if present (v0.4.2+ canonical URIs)\n // We only embed crucible schemas - other modules cannot be resolved locally\n if (relativePath.startsWith(\"crucible/\")) {\n relativePath = relativePath.slice(\"crucible/\".length);\n }\n\n // Check if it's a config taxonomy reference\n if (relativePath.startsWith(\"config/taxonomy/\")) {\n resolvedPath = join(\n repoRoot,\n \"config\",\n \"crucible-ts\",\n \"taxonomy\",\n relativePath.split(\"/\").pop() || \"\",\n );\n } else {\n // Schema reference - map to schemas/crucible-ts/\n resolvedPath = join(repoRoot, \"schemas\", \"crucible-ts\", relativePath);\n }\n }\n // Handle relative paths (e.g., \"../../../../config/taxonomy/metrics.yaml\")\n else if (uri.startsWith(\"../../\") || uri.startsWith(\"../\")) {\n // Resolve relative to schemas/crucible-ts/observability/metrics/v1.0.0/\n // (where metrics-event.schema.json is located)\n const schemaBase = join(\n repoRoot,\n \"schemas\",\n \"crucible-ts\",\n \"observability\",\n \"metrics\",\n \"v1.0.0\",\n );\n resolvedPath = join(schemaBase, uri);\n }\n // Handle file:// URIs\n else if (uri.startsWith(\"file://\")) {\n resolvedPath = fileURLToPath(uri);\n }\n // Unhandled URI scheme\n else {\n throw new Error(`Cannot load remote schema: ${uri}`);\n }\n\n // Read and parse the file\n const content = await readFile(resolvedPath, \"utf-8\");\n const ext = resolvedPath.split(\".\").pop()?.toLowerCase();\n\n if (ext === \"yaml\" || ext === \"yml\") {\n return parseYAML(content) as Record<string, unknown>;\n }\n return JSON.parse(content) as Record<string, unknown>;\n}\n\n/**\n * Resolve JSON Schema dialect from schema content.\n */\nfunction detectDialect(schema: unknown): JsonSchemaDialect {\n if (schema && typeof schema === \"object\" && !Array.isArray(schema)) {\n const maybeSchema = schema as Record<string, unknown>;\n const declared = (maybeSchema as { $schema?: unknown }).$schema;\n\n if (typeof declared === \"string\") {\n if (declared.includes(\"draft-04\")) return \"draft-04\";\n if (declared.includes(\"draft-06\")) return \"draft-06\";\n if (declared.includes(\"draft-07\")) return \"draft-07\";\n if (declared.includes(\"draft/2019-09\")) return \"draft-2019-09\";\n if (declared.includes(\"draft/2020-12\")) return \"draft-2020-12\";\n }\n }\n\n // Default to 2020-12 in Fulmen ecosystem.\n return \"draft-2020-12\";\n}\n\n/**\n * Create AJV instance for a specific dialect\n */\nfunction createAjv(dialect: JsonSchemaDialect): Ajv {\n const AjvCtor =\n dialect === \"draft-2020-12\"\n ? Ajv2020\n : dialect === \"draft-2019-09\"\n ? Ajv2019\n : dialect === \"draft-04\"\n ? (AjvDraft04 as unknown as typeof Ajv)\n : Ajv;\n\n const ajv = new AjvCtor({\n strict: false,\n allErrors: true,\n verbose: true,\n // Allow schemas with $id to be added without replacing existing ones\n addUsedSchema: false,\n // draft-04 uses \"id\"; later drafts use \"$id\"\n schemaId: dialect === \"draft-04\" ? \"id\" : \"$id\",\n // Enable async schema loading for YAML references\n loadSchema: loadReferencedSchema,\n });\n\n applyFulmenAjvFormats(ajv);\n\n return ajv;\n}\n\n/**\n * Get or create AJV instance for a dialect, ensuring metaschemas are loaded.\n */\nasync function getAjv(dialect: JsonSchemaDialect): Promise<Ajv> {\n const existing = ajvInstances.get(dialect);\n if (existing) {\n const ready = metaschemaReady.get(dialect);\n if (ready) await ready;\n return existing;\n }\n\n const ajv = createAjv(dialect);\n ajvInstances.set(dialect, ajv);\n\n const readyPromise = Promise.all([loadVocabularySchemas(dialect), loadMetaSchema(dialect)])\n .then(([vocabSchemas, metaSchema]) => {\n // Add vocabulary schemas first (referenced by meta schema)\n for (const vocabSchema of vocabSchemas) {\n try {\n ajv.addMetaSchema(vocabSchema);\n } catch {\n // Already added or incompatible with Ajv's built-ins\n }\n }\n\n try {\n ajv.addMetaSchema(metaSchema);\n } catch {\n // Already added or incompatible with Ajv's built-ins\n }\n })\n .catch((error) => {\n throw new Error(`Failed to load metaschemas (${dialect}): ${error}`);\n });\n\n metaschemaReady.set(dialect, readyPromise);\n await readyPromise;\n\n return ajv;\n}\n\n/**\n * Compile a schema for validation\n */\nexport async function compileSchema(\n schema: SchemaInput,\n options: { aliases?: string[] } = {},\n): Promise<CompiledValidator> {\n const baseKey = typeof schema === \"string\" ? schema : JSON.stringify(schema);\n\n let parsedSchema: unknown;\n if (typeof schema === \"string\") {\n try {\n parsedSchema = JSON.parse(schema);\n } catch {\n // Try YAML if JSON parsing fails\n parsedSchema = parseYAML(schema);\n }\n } else if (Buffer.isBuffer(schema)) {\n const content = schema.toString(\"utf-8\");\n try {\n parsedSchema = JSON.parse(content);\n } catch {\n parsedSchema = parseYAML(content);\n }\n } else {\n parsedSchema = schema;\n }\n\n const dialect = detectDialect(parsedSchema);\n const ajv = await getAjv(dialect);\n\n const cacheKey = `${dialect}:${baseKey}`;\n const cached = schemaCache.get(cacheKey);\n if (cached !== undefined) {\n return cached;\n }\n\n try {\n // Register schema aliases (e.g., alternate $id values) before compile to support relative refs\n if (options.aliases && options.aliases.length > 0) {\n for (const alias of options.aliases) {\n if (alias && ajv.getSchema(alias) === undefined) {\n try {\n if (typeof parsedSchema === \"object\" && parsedSchema !== null) {\n ajv.addSchema(parsedSchema as Record<string, unknown>, alias);\n }\n } catch {\n // Ignore if alias already registered or invalid\n }\n }\n }\n }\n\n const validator =\n typeof parsedSchema === \"boolean\"\n ? ajv.compile(parsedSchema)\n : await ajv.compileAsync(parsedSchema as Record<string, unknown>);\n\n // Cache the compiled validator\n schemaCache.set(cacheKey, validator as CompiledValidator);\n\n return validator as CompiledValidator;\n } catch (error) {\n throw SchemaValidationError.parseFailed(\n {\n type: \"string\",\n content: typeof schema === \"string\" ? schema : JSON.stringify(schema),\n },\n error as Error,\n );\n }\n}\n\n/**\n * Validate data against a compiled schema\n */\nexport function validateData(data: unknown, validator: CompiledValidator): SchemaValidationResult {\n const valid = validator(data);\n\n const result: SchemaValidationResult = {\n valid,\n diagnostics: [],\n source: \"ajv\",\n };\n\n if (!valid && validator.errors) {\n const errors = validator.errors;\n if (Array.isArray(errors)) {\n result.diagnostics = errors.map((error) =>\n createDiagnostic(\n error.instancePath || \"\",\n error.message || \"Validation failed\",\n error.keyword || \"unknown\",\n \"ERROR\",\n \"ajv\",\n ),\n );\n }\n metrics.counter(\"schema_validation_errors\").inc();\n } else {\n metrics.counter(\"schema_validations\").inc();\n }\n\n return result;\n}\n\n/**\n * Validate file against a schema\n */\nexport async function validateFile(\n filePath: string,\n validator: CompiledValidator,\n): Promise<SchemaValidationResult> {\n try {\n const content = await readFile(filePath, \"utf-8\");\n let data: unknown;\n\n try {\n data = JSON.parse(content);\n } catch {\n // Try YAML if JSON parsing fails\n data = parseYAML(content);\n }\n\n return validateData(data, validator);\n } catch (error) {\n if (error instanceof SchemaValidationError) {\n throw error;\n }\n throw SchemaValidationError.validationFailed(\n filePath,\n [\n createDiagnostic(\n \"\",\n `Failed to read or parse file: ${(error as Error).message}`,\n \"file-read\",\n \"ERROR\",\n \"ajv\",\n ),\n ],\n { type: \"file\", id: filePath },\n );\n }\n}\n\n/**\n * Validate a schema document itself\n */\nexport async function validateSchema(schema: SchemaInput): Promise<SchemaValidationResult> {\n try {\n // Parse schema so we can both meta-validate and compile with dialect-specific Ajv.\n let parsedSchema: unknown;\n if (typeof schema === \"string\") {\n try {\n parsedSchema = JSON.parse(schema);\n } catch {\n parsedSchema = parseYAML(schema);\n }\n } else if (Buffer.isBuffer(schema)) {\n const content = schema.toString(\"utf-8\");\n try {\n parsedSchema = JSON.parse(content);\n } catch {\n parsedSchema = parseYAML(content);\n }\n } else {\n parsedSchema = schema;\n }\n\n const dialect = detectDialect(parsedSchema);\n const ajv = await getAjv(dialect);\n\n // 1) Meta validation against declared dialect\n const metaValid = ajv.validateSchema(parsedSchema as AnySchema);\n if (!metaValid && ajv.errors) {\n const diagnostics = ajv.errors.map((error) =>\n createDiagnostic(\n error.instancePath || \"\",\n error.message || \"Schema meta-validation failed\",\n error.keyword || \"unknown\",\n \"ERROR\",\n \"ajv\",\n ),\n );\n\n return { valid: false, diagnostics, source: \"ajv\" };\n }\n\n // 2) Compilation check (refs resolvable, keywords supported)\n await compileSchema(parsedSchema as SchemaInput);\n\n return {\n valid: true,\n diagnostics: [],\n source: \"ajv\",\n };\n } catch (error) {\n if (error instanceof SchemaValidationError) {\n return {\n valid: false,\n diagnostics: error.diagnostics,\n source: \"ajv\",\n };\n }\n\n return {\n valid: false,\n diagnostics: [\n createDiagnostic(\n \"\",\n `Schema validation failed: ${(error as Error).message}`,\n \"schema-validation\",\n \"ERROR\",\n \"ajv\",\n ),\n ],\n source: \"ajv\",\n };\n }\n}\n\n/**\n * Clear schema cache\n */\nexport function clearCache(): void {\n schemaCache.clear();\n // Keep Ajv instances cached; they hold metaschemas. Tests can still clear schema cache.\n}\n\n/**\n * Get schema cache size\n */\nexport function getCacheSize(): number {\n return schemaCache.size;\n}\n\n/**\n * Load schema by ID from registry and compile\n */\nexport async function compileSchemaById(\n schemaId: string,\n registryOptions?: SchemaRegistryOptions,\n): Promise<CompiledValidator> {\n try {\n const registry = getSchemaRegistry(registryOptions);\n const metadata = await registry.getSchema(schemaId);\n\n const content = await readFile(metadata.path, \"utf-8\");\n const aliases: string[] = [];\n\n const normalizedRelativePath = metadata.relativePath.replace(/\\\\/g, \"/\");\n if (normalizedRelativePath) {\n // Per Canonical URI Resolution Standard (v0.4.2+), include crucible/ module prefix\n aliases.push(\n new URL(`crucible/${normalizedRelativePath}`, \"https://schemas.fulmenhq.dev/\").toString(),\n );\n }\n\n return compileSchema(content, { aliases });\n } catch (error) {\n metrics.counter(\"schema_validation_errors\").inc();\n throw error;\n }\n}\n\n/**\n * Validate data against a schema ID from registry\n */\nexport async function validateDataBySchemaId(\n data: unknown,\n schemaId: string,\n registryOptions?: SchemaRegistryOptions,\n): Promise<SchemaValidationResult> {\n try {\n const validator = await compileSchemaById(schemaId, registryOptions);\n return validateData(data, validator);\n } catch (error) {\n metrics.counter(\"schema_validation_errors\").inc();\n throw error;\n }\n}\n\n/**\n * Validate file against a schema ID from registry\n */\nexport async function validateFileBySchemaId(\n filePath: string,\n schemaId: string,\n registryOptions?: SchemaRegistryOptions,\n): Promise<SchemaValidationResult> {\n try {\n const validator = await compileSchemaById(schemaId, registryOptions);\n return validateFile(filePath, validator);\n } catch (error) {\n metrics.counter(\"schema_validation_errors\").inc();\n throw error;\n }\n}\n","/**\n * Schema CLI - Commander-based CLI for schema operations\n *\n * Provides command-line interface for schema discovery, validation,\n * and normalization operations. This is a developer tool for exploration\n * and testing, not for production use.\n */\n\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport { Command } from \"commander\";\nimport { isGoneatAvailable, runGoneatValidation } from \"./goneat-bridge.js\";\nimport { compareSchemas, normalizeSchema } from \"./normalizer.js\";\nimport { getSchemaRegistry, listSchemas } from \"./registry.js\";\nimport type { CLIOptions, SchemaValidationResult } from \"./types.js\";\nimport { formatDiagnostics } from \"./utils.js\";\nimport { validateFileBySchemaId } from \"./validator.js\";\n\n/**\n * Create CLI command structure\n */\nexport function createCLI(options: CLIOptions = {}): Command {\n const program = new Command();\n\n program\n .name(\"tsfulmen-schema\")\n .description(\"Schema validation and discovery CLI for Fulmen (developer tool)\")\n .version(\"0.1.0\");\n\n // List schemas command\n program\n .command(\"list\")\n .description(\"List available schemas from registry\")\n .argument(\"[prefix]\", \"Filter schemas by prefix\")\n .option(\"--base-dir <path>\", \"Override schema base directory\")\n .action(async (prefix?: string, cmdOptions?: { baseDir?: string }) => {\n try {\n const schemas = await listSchemas(prefix, {\n baseDir: cmdOptions?.baseDir || options.baseDir,\n });\n\n if (schemas.length === 0) {\n console.log(\"No schemas found\");\n return;\n }\n\n console.log(`Found ${schemas.length} schema(s):\\n`);\n for (const schema of schemas) {\n console.log(` ${schema.id}`);\n console.log(` Format: ${schema.format}`);\n console.log(` Path: ${schema.relativePath}`);\n if (schema.description) {\n console.log(` Description: ${schema.description}`);\n }\n console.log();\n }\n } catch (error) {\n console.error(\"Error listing schemas:\", (error as Error).message);\n process.exit(1);\n }\n });\n\n // Show schema command\n program\n .command(\"show\")\n .description(\"Show schema details\")\n .requiredOption(\"--schema-id <id>\", \"Schema ID to show\")\n .option(\"--base-dir <path>\", \"Override schema base directory\")\n .action(async (cmdOptions: { schemaId: string; baseDir?: string }) => {\n try {\n const registry = getSchemaRegistry({\n baseDir: cmdOptions.baseDir || options.baseDir,\n });\n const schema = await registry.getSchema(cmdOptions.schemaId);\n\n console.log(\"Schema Details:\\n\");\n console.log(` ID: ${schema.id}`);\n console.log(` Format: ${schema.format}`);\n console.log(` Path: ${schema.path}`);\n console.log(` Relative Path: ${schema.relativePath}`);\n if (schema.version) {\n console.log(` Version: ${schema.version}`);\n }\n if (schema.description) {\n console.log(` Description: ${schema.description}`);\n }\n if (schema.schemaDraft) {\n console.log(` Schema Draft: ${schema.schemaDraft}`);\n }\n\n // Read and display schema content\n const content = await readFile(schema.path, \"utf-8\");\n console.log(\"\\nSchema Content:\");\n console.log(content);\n } catch (error) {\n console.error(\"Error showing schema:\", (error as Error).message);\n process.exit(1);\n }\n });\n\n // Validate data command\n program\n .command(\"validate\")\n .description(\"Validate data file against schema\")\n .requiredOption(\"--schema-id <id>\", \"Schema ID to validate against\")\n .argument(\"<file>\", \"Data file to validate\")\n .option(\"--use-goneat\", \"Use goneat for validation (requires goneat binary)\")\n .option(\"--goneat-path <path>\", \"Path to goneat binary\")\n .option(\"--base-dir <path>\", \"Override schema base directory\")\n .action(\n async (\n file: string,\n cmdOptions: {\n schemaId: string;\n useGoneat?: boolean;\n goneatPath?: string;\n baseDir?: string;\n },\n ) => {\n try {\n let result: SchemaValidationResult;\n\n if (cmdOptions.useGoneat) {\n // Check goneat availability\n const available = await isGoneatAvailable(cmdOptions.goneatPath);\n if (!available) {\n console.error(\"❌ goneat not available. Install goneat or remove --use-goneat flag.\");\n console.error(\" AJV validation (default) works without external dependencies.\");\n process.exit(1);\n }\n\n // Get schema path\n const registry = getSchemaRegistry({\n baseDir: cmdOptions.baseDir || options.baseDir,\n });\n const schema = await registry.getSchema(cmdOptions.schemaId);\n\n console.log(\"Using goneat validation...\");\n result = await runGoneatValidation(schema.path, file, cmdOptions.goneatPath);\n } else {\n // Use AJV validation (default, library implementation)\n console.log(\"Using AJV validation...\");\n result = await validateFileBySchemaId(file, cmdOptions.schemaId, {\n baseDir: cmdOptions.baseDir || options.baseDir,\n });\n }\n\n if (result.valid) {\n console.log(`✅ Validation passed (${result.source})`);\n process.exit(0);\n } else {\n console.log(`❌ Validation failed (${result.source})`);\n console.log(\"\\nDiagnostics:\");\n console.log(formatDiagnostics(result.diagnostics));\n process.exit(1);\n }\n } catch (error) {\n console.error(\"Error validating file:\", (error as Error).message);\n process.exit(1);\n }\n },\n );\n\n // Validate schema command\n program\n .command(\"validate-schema\")\n .description(\"Validate a schema file itself\")\n .argument(\"<file>\", \"Schema file to validate\")\n .action(async (file: string) => {\n try {\n const content = await readFile(file, \"utf-8\");\n const { validateSchema } = await import(\"./validator.js\");\n const result = await validateSchema(content);\n\n if (result.valid) {\n console.log(\"✅ Schema is valid\");\n process.exit(0);\n } else {\n console.log(\"❌ Schema is invalid\");\n console.log(\"\\nDiagnostics:\");\n console.log(formatDiagnostics(result.diagnostics));\n process.exit(1);\n }\n } catch (error) {\n console.error(\"Error validating schema:\", (error as Error).message);\n process.exit(1);\n }\n });\n\n // Normalize schema command\n program\n .command(\"normalize\")\n .description(\"Normalize schema to canonical JSON format\")\n .argument(\"<file>\", \"Schema file to normalize\")\n .option(\"--compact\", \"Output compact JSON (no formatting)\")\n .option(\"-o, --output <file>\", \"Write to output file instead of stdout\")\n .action(async (file: string, cmdOptions: { compact?: boolean; output?: string }) => {\n try {\n const content = await readFile(file, \"utf-8\");\n const normalized = normalizeSchema(content, {\n compact: cmdOptions.compact,\n });\n\n if (cmdOptions.output) {\n await writeFile(cmdOptions.output, normalized, \"utf-8\");\n console.log(`✅ Normalized schema written to ${cmdOptions.output}`);\n } else {\n console.log(normalized);\n }\n } catch (error) {\n console.error(\"Error normalizing schema:\", (error as Error).message);\n process.exit(1);\n }\n });\n\n // Compare schemas command\n program\n .command(\"compare\")\n .description(\"Compare two schemas for semantic equality\")\n .argument(\"<file1>\", \"First schema file\")\n .argument(\"<file2>\", \"Second schema file\")\n .option(\"--show-normalized\", \"Show normalized outputs\")\n .action(async (file1: string, file2: string, cmdOptions: { showNormalized?: boolean }) => {\n try {\n const content1 = await readFile(file1, \"utf-8\");\n const content2 = await readFile(file2, \"utf-8\");\n\n const result = compareSchemas(content1, content2);\n\n if (result.equal) {\n console.log(\"✅ Schemas are semantically equal\");\n } else {\n console.log(\"❌ Schemas differ\");\n }\n\n if (cmdOptions.showNormalized) {\n console.log(\"\\nNormalized Schema 1:\");\n console.log(result.normalizedA);\n console.log(\"\\nNormalized Schema 2:\");\n console.log(result.normalizedB);\n }\n\n process.exit(result.equal ? 0 : 1);\n } catch (error) {\n console.error(\"Error comparing schemas:\", (error as Error).message);\n process.exit(1);\n }\n });\n\n // Export schema command\n program\n .command(\"export\")\n .description(\"Export schema from registry to file with provenance\")\n .requiredOption(\"--schema-id <id>\", \"Schema ID to export\")\n .requiredOption(\"--out <path>\", \"Output file path\")\n .option(\"--force\", \"Overwrite existing file\", false)\n .option(\"--no-provenance\", \"Exclude provenance metadata\")\n .option(\"--no-validate\", \"Skip schema validation before export\")\n .option(\"--format <format>\", \"Export format (json|yaml|auto)\", \"auto\")\n .option(\"--base-dir <path>\", \"Override schema base directory\")\n .action(\n async (cmdOptions: {\n schemaId: string;\n out: string;\n force?: boolean;\n provenance?: boolean;\n validate?: boolean;\n format?: string;\n baseDir?: string;\n }) => {\n try {\n const { exportSchema } = await import(\"./export.js\");\n const { exitCodes } = await import(\"../foundry/index.js\");\n\n const result = await exportSchema({\n schemaId: cmdOptions.schemaId,\n outPath: cmdOptions.out,\n includeProvenance: cmdOptions.provenance ?? true,\n validate: cmdOptions.validate ?? true,\n overwrite: cmdOptions.force ?? false,\n format: (cmdOptions.format as \"json\" | \"yaml\" | \"auto\") ?? \"auto\",\n baseDir: cmdOptions.baseDir || options.baseDir,\n });\n\n console.log(\"✅ Schema exported successfully\");\n console.log(` Schema ID: ${result.schemaId}`);\n console.log(` Output: ${result.outPath}`);\n console.log(` Format: ${result.format}`);\n\n if (result.provenance) {\n console.log(\"\\nProvenance:\");\n console.log(` Crucible: ${result.provenance.crucible_version}`);\n console.log(` Library: ${result.provenance.library_version}`);\n if (result.provenance.revision) {\n console.log(` Revision: ${result.provenance.revision}`);\n }\n console.log(` Exported: ${result.provenance.exported_at}`);\n }\n\n process.exit(exitCodes.EXIT_SUCCESS);\n } catch (error) {\n const { exitCodes } = await import(\"../foundry/index.js\");\n const { SchemaExportError, SchemaValidationError, ExportErrorReason } = await import(\n \"./errors.js\"\n );\n\n console.error(\"❌ Schema export failed:\", (error as Error).message);\n\n // Map specific error types to appropriate exit codes\n if (error instanceof SchemaExportError) {\n if (error.outPath) {\n console.error(` Output path: ${error.outPath}`);\n }\n\n // Use error reason for type-safe exit code mapping\n switch (error.reason) {\n case ExportErrorReason.FILE_EXISTS:\n case ExportErrorReason.WRITE_FAILED:\n process.exit(exitCodes.EXIT_FILE_WRITE_ERROR);\n break;\n\n case ExportErrorReason.INVALID_FORMAT:\n process.exit(exitCodes.EXIT_INVALID_ARGUMENT);\n break;\n\n default:\n // PROVENANCE_FAILED, UNKNOWN, and any future reasons\n process.exit(exitCodes.EXIT_FAILURE);\n }\n }\n\n if (error instanceof SchemaValidationError) {\n // Schema not found or validation failed\n const errorMsg = error.message.toLowerCase();\n\n if (errorMsg.includes(\"not found\")) {\n process.exit(exitCodes.EXIT_FILE_NOT_FOUND);\n }\n\n // Validation failures\n process.exit(exitCodes.EXIT_DATA_INVALID);\n }\n\n process.exit(exitCodes.EXIT_FAILURE);\n }\n },\n );\n\n // Identity show command\n program\n .command(\"identity-show\")\n .description(\"Show application identity from .fulmen/app.yaml\")\n .option(\"--path <path>\", \"Explicit path to app.yaml\")\n .option(\"--json\", \"Output as JSON\")\n .action(async (cmdOptions: { path?: string; json?: boolean }) => {\n try {\n const { loadIdentity } = await import(\"../appidentity/loader.js\");\n const { exitCodes } = await import(\"../foundry/index.js\");\n\n const identity = await loadIdentity({ path: cmdOptions.path });\n\n if (cmdOptions.json) {\n console.log(JSON.stringify(identity, null, 2));\n } else {\n console.log(\"Application Identity:\\n\");\n console.log(` Binary Name: ${identity.app.binary_name}`);\n console.log(` Vendor: ${identity.app.vendor}`);\n console.log(` Env Prefix: ${identity.app.env_prefix}`);\n console.log(` Config Name: ${identity.app.config_name}`);\n console.log(` Description: ${identity.app.description}`);\n\n if (identity.metadata) {\n console.log(\"\\nMetadata:\");\n if (identity.metadata.license) {\n console.log(` License: ${identity.metadata.license}`);\n }\n if (identity.metadata.repository_category) {\n console.log(` Category: ${identity.metadata.repository_category}`);\n }\n if (identity.metadata.telemetry_namespace) {\n console.log(` Telemetry: ${identity.metadata.telemetry_namespace}`);\n }\n if (identity.metadata.project_url) {\n console.log(` Project URL: ${identity.metadata.project_url}`);\n }\n }\n }\n\n process.exit(exitCodes.EXIT_SUCCESS);\n } catch (error) {\n const { exitCodes } = await import(\"../foundry/index.js\");\n const { AppIdentityError } = await import(\"../appidentity/errors.js\");\n\n console.error(\"❌ Failed to load identity:\", (error as Error).message);\n\n if (error instanceof AppIdentityError) {\n if (error.message.includes(\"not found\")) {\n process.exit(exitCodes.EXIT_FILE_NOT_FOUND);\n }\n if (error.message.includes(\"Invalid\") || error.message.includes(\"validation\")) {\n process.exit(exitCodes.EXIT_DATA_INVALID);\n }\n }\n\n process.exit(exitCodes.EXIT_FAILURE);\n }\n });\n\n // Identity validate command\n program\n .command(\"identity-validate\")\n .description(\"Validate application identity against schema\")\n .argument(\"[file]\", \"Path to app.yaml (defaults to discovery)\")\n .action(async (file?: string) => {\n try {\n const { loadIdentity } = await import(\"../appidentity/loader.js\");\n const { exitCodes } = await import(\"../foundry/index.js\");\n\n console.log(\"Validating application identity...\");\n\n const identity = await loadIdentity({ path: file });\n\n console.log(\"✅ Identity is valid\");\n console.log(` Binary: ${identity.app.binary_name}`);\n console.log(` Vendor: ${identity.app.vendor}`);\n\n process.exit(exitCodes.EXIT_SUCCESS);\n } catch (error) {\n const { exitCodes } = await import(\"../foundry/index.js\");\n const { AppIdentityError } = await import(\"../appidentity/errors.js\");\n\n console.error(\"❌ Identity validation failed:\", (error as Error).message);\n\n if (error instanceof AppIdentityError) {\n if (error.message.includes(\"not found\")) {\n process.exit(exitCodes.EXIT_FILE_NOT_FOUND);\n }\n if (error.message.includes(\"Invalid\") || error.message.includes(\"validation\")) {\n process.exit(exitCodes.EXIT_DATA_INVALID);\n }\n }\n\n process.exit(exitCodes.EXIT_FAILURE);\n }\n });\n\n return program;\n}\n","/**\n * Schema export utilities - implements schema export with provenance\n */\n\nimport { access, mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname, extname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { parse as parseYAML, stringify as stringifyYAML } from \"yaml\";\nimport { SchemaExportError, SchemaValidationError } from \"./errors.js\";\nimport { getSchemaRegistry } from \"./registry.js\";\nimport type {\n ExportSchemaOptions,\n ExportSchemaResult,\n SchemaExportFormat,\n SchemaProvenanceMetadata,\n} from \"./types.js\";\nimport { validateSchema } from \"./validator.js\";\n\n/**\n * Extract provenance metadata from Crucible sync metadata\n */\nasync function extractProvenanceMetadata(schemaId: string): Promise<SchemaProvenanceMetadata> {\n try {\n // Read Crucible metadata using proper path resolution\n const __filename = fileURLToPath(import.meta.url);\n const __dirname = dirname(__filename);\n const metadataPath = join(__dirname, \"..\", \"..\", \".crucible\", \"metadata\", \"metadata.yaml\");\n const metadataContent = await readFile(metadataPath, \"utf-8\");\n\n // Parse YAML properly to avoid brittle regex matching\n const metadata = parseYAML(metadataContent) as {\n sources?: Array<{\n name?: string;\n version?: string;\n commit?: string;\n }>;\n };\n\n // Extract Crucible source metadata (first source is typically 'crucible')\n const crucibleSource = metadata.sources?.[0];\n const crucibleVersion = crucibleSource?.version || \"unknown\";\n const revision = crucibleSource?.commit;\n\n // Read library version from package.json\n const pkgPath = join(__dirname, \"..\", \"..\", \"package.json\");\n const pkgContent = await readFile(pkgPath, \"utf-8\");\n const pkg = JSON.parse(pkgContent) as { version: string };\n\n return {\n schema_id: schemaId,\n crucible_version: crucibleVersion,\n library_version: pkg.version,\n revision: revision,\n exported_at: new Date().toISOString(),\n export_source: \"tsfulmen\",\n };\n } catch (error) {\n throw SchemaExportError.provenanceFailed((error as Error).message, error as Error);\n }\n}\n\n/**\n * Embed provenance metadata in schema content\n */\nfunction embedProvenance(\n schemaContent: Record<string, unknown>,\n provenance: SchemaProvenanceMetadata,\n format: SchemaExportFormat,\n): string {\n if (format === \"json\") {\n // For JSON: embed under $comment[\"x-crucible-source\"]\n const withProvenance = {\n ...schemaContent,\n $comment: {\n ...(typeof schemaContent.$comment === \"object\" ? schemaContent.$comment : {}),\n \"x-crucible-source\": provenance,\n },\n };\n return JSON.stringify(withProvenance, null, 2);\n }\n\n // For YAML: prepend comment block\n const yamlContent = stringifyYAML(schemaContent, {\n indent: 2,\n lineWidth: 0,\n });\n\n const provenanceComment = [\n \"# x-crucible-source:\",\n `# schema_id: ${provenance.schema_id}`,\n `# crucible_version: ${provenance.crucible_version}`,\n `# library_version: ${provenance.library_version}`,\n ...(provenance.revision ? [`# revision: ${provenance.revision}`] : []),\n `# exported_at: ${provenance.exported_at}`,\n `# export_source: ${provenance.export_source}`,\n \"\",\n ].join(\"\\n\");\n\n return provenanceComment + yamlContent;\n}\n\n/**\n * Detect export format from file extension or explicit option\n */\nfunction detectFormat(outPath: string, formatOption?: SchemaExportFormat): SchemaExportFormat {\n if (formatOption && formatOption !== \"auto\") {\n return formatOption;\n }\n\n const ext = extname(outPath).toLowerCase();\n switch (ext) {\n case \".json\":\n return \"json\";\n case \".yaml\":\n case \".yml\":\n return \"yaml\";\n default:\n throw SchemaExportError.invalidFormat(ext, outPath);\n }\n}\n\n/**\n * Export schema from registry to file with provenance\n *\n * @param options - Export options\n * @returns Export result with metadata\n *\n * @throws {SchemaExportError} If export fails\n * @throws {SchemaValidationError} If schema not found or validation fails\n *\n * @example\n * ```typescript\n * import { exportSchema } from '@fulmenhq/tsfulmen/schema';\n *\n * await exportSchema({\n * schemaId: 'library/foundry/v1.0.0/exit-codes',\n * outPath: './schemas/exit-codes.schema.json',\n * includeProvenance: true,\n * validate: true,\n * });\n * ```\n */\nexport async function exportSchema(options: ExportSchemaOptions): Promise<ExportSchemaResult> {\n const {\n schemaId,\n outPath,\n includeProvenance = true,\n validate = true,\n overwrite = false,\n format: formatOption,\n baseDir,\n } = options;\n\n // Detect output format\n const format = detectFormat(outPath, formatOption);\n\n // Check if file exists\n if (!overwrite) {\n try {\n await access(outPath);\n throw SchemaExportError.fileExists(outPath);\n } catch (error) {\n // File doesn't exist - proceed\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") {\n throw error;\n }\n }\n }\n\n // Get schema from registry\n const registry = getSchemaRegistry({ baseDir });\n const schema = await registry.getSchema(schemaId);\n\n // Read schema content\n const schemaContent = await readFile(schema.path, \"utf-8\");\n\n // Validate if requested\n if (validate) {\n const validationResult = await validateSchema(schemaContent);\n if (!validationResult.valid) {\n throw SchemaValidationError.validationFailed(schemaId, validationResult.diagnostics, {\n type: \"file\",\n id: schema.path,\n });\n }\n }\n\n // Parse schema content\n let schemaObject: Record<string, unknown>;\n try {\n schemaObject = JSON.parse(schemaContent) as Record<string, unknown>;\n } catch {\n schemaObject = parseYAML(schemaContent) as Record<string, unknown>;\n }\n\n // Freeze schema object to prevent mutation\n Object.freeze(schemaObject);\n\n let provenance: SchemaProvenanceMetadata | undefined;\n let outputContent: string;\n\n if (includeProvenance) {\n // Extract provenance metadata\n provenance = await extractProvenanceMetadata(schemaId);\n\n // Embed provenance in output\n outputContent = embedProvenance(schemaObject, provenance, format);\n } else {\n // Export without provenance\n if (format === \"json\") {\n outputContent = JSON.stringify(schemaObject, null, 2);\n } else {\n outputContent = stringifyYAML(schemaObject, { indent: 2, lineWidth: 0 });\n }\n }\n\n // Ensure output directory exists\n await mkdir(dirname(outPath), { recursive: true });\n\n // Write to file\n try {\n await writeFile(outPath, outputContent, \"utf-8\");\n } catch (error) {\n throw SchemaExportError.writeFailed(outPath, error as Error);\n }\n\n return {\n success: true,\n schemaId,\n outPath,\n format,\n includeProvenance,\n provenance,\n };\n}\n\n/**\n * Strip provenance metadata from schema content\n *\n * This helper is useful for comparing exported schemas with runtime\n * schemas or validating that provenance doesn't affect schema semantics.\n *\n * @param content - Schema content (JSON or YAML string)\n * @returns Schema content without provenance metadata\n *\n * @example\n * ```typescript\n * import { stripProvenance } from '@fulmenhq/tsfulmen/schema';\n *\n * const exported = await readFile('./schema.json', 'utf-8');\n * const withoutProvenance = stripProvenance(exported);\n * ```\n */\nexport function stripProvenance(content: string): string {\n try {\n // Try parsing as JSON\n const parsed = JSON.parse(content) as Record<string, unknown>;\n\n // Remove provenance from $comment\n if (parsed.$comment && typeof parsed.$comment === \"object\") {\n const comment = { ...parsed.$comment } as Record<string, unknown>;\n delete comment[\"x-crucible-source\"];\n\n // Remove $comment entirely if it's now empty\n if (Object.keys(comment).length === 0) {\n delete parsed.$comment;\n } else {\n parsed.$comment = comment;\n }\n }\n\n return JSON.stringify(parsed, null, 2);\n } catch {\n // YAML format - strip comment lines\n const lines = content.split(\"\\n\");\n const filtered = lines.filter((line) => {\n const trimmed = line.trim();\n return !(\n trimmed.startsWith(\"# x-crucible-source:\") ||\n (trimmed.startsWith(\"# \") &&\n /^#\\s+(schema_id|crucible_version|library_version|revision|exported_at|export_source):/.test(\n trimmed,\n ))\n );\n });\n\n // Remove leading blank lines\n while (filtered.length > 0 && filtered[0]?.trim() === \"\") {\n filtered.shift();\n }\n\n return filtered.join(\"\\n\");\n }\n}\n","/**\n * Schema validation module - implements Fulmen Schema Validation Standard\n *\n * Provides schema discovery, validation, and normalization utilities for Crucible schemas\n * with JSON Schema 2020-12 support and optional goneat integration.\n */\n\nexport const VERSION = \"0.1.0\";\n\nexport {\n applyFulmenAjvFormats,\n type FulmenAjvFormatsOptions,\n} from \"./ajv-formats.js\";\n\n// CLI exports\nexport { createCLI } from \"./cli.js\";\n// Error exports\nexport * from \"./errors.js\";\n// Export exports\nexport { exportSchema, stripProvenance } from \"./export.js\";\n// Goneat bridge exports (CLI-only, optional)\nexport {\n detectGoneat,\n isGoneatAvailable,\n runGoneatValidation,\n} from \"./goneat-bridge.js\";\n// Normalizer exports\nexport { compareSchemas, normalizeSchema } from \"./normalizer.js\";\n// Registry exports\nexport {\n getSchema,\n getSchemaByPath,\n getSchemaRegistry,\n hasSchema,\n listSchemas,\n SchemaRegistry,\n} from \"./registry.js\";\n// Core exports\nexport type {\n AjvError,\n CLIOptions,\n CompiledValidator,\n ExportSchemaOptions,\n ExportSchemaResult,\n SchemaComparisonResult,\n SchemaExportFormat,\n SchemaFormat,\n SchemaInput,\n SchemaMetadata,\n SchemaNormalizationOptions,\n SchemaProvenanceMetadata,\n SchemaRegistryOptions,\n SchemaSource,\n SchemaValidationDiagnostic,\n SchemaValidationOptions,\n SchemaValidationResult,\n} from \"./types.js\";\n// Utility exports\nexport {\n countDiagnostics,\n createDiagnostic,\n formatDiagnostics,\n formatValidationResult,\n groupDiagnosticsBySeverity,\n isValidationError,\n normalizePointer,\n} from \"./utils.js\";\n// Validator exports\nexport {\n clearCache,\n compileSchema,\n compileSchemaById,\n getCacheSize,\n validateData,\n validateDataBySchemaId,\n validateFile,\n validateFileBySchemaId,\n validateSchema,\n} from \"./validator.js\";\n","/**\n * Environment variable alias utilities.\n *\n * Workhorse templates sometimes support both canonical nested env vars and\n * convenience aliases (e.g. TUVAN_SERVER_PORT vs TUVAN_PORT).\n *\n * This helper standardizes alias resolution and conflict reporting.\n */\n\nexport interface EnvAliasConflict {\n canonicalKey: string;\n aliasKey: string;\n canonicalValue: string;\n aliasValue: string;\n}\n\nexport interface ResolveEnvAliasesResult {\n env: Record<string, string | undefined>;\n applied: Array<{ aliasKey: string; canonicalKey: string }>;\n conflicts: EnvAliasConflict[];\n}\n\n/**\n * Resolve env var aliases into canonical keys.\n *\n * - If canonical key is unset and alias is set, the alias value is copied to canonical.\n * - If both are set and differ, a conflict is recorded (canonical is left unchanged).\n */\nexport function resolveEnvAliases(\n env: Record<string, string | undefined>,\n aliasToCanonical: Record<string, string>,\n): ResolveEnvAliasesResult {\n const out: Record<string, string | undefined> = { ...env };\n const applied: Array<{ aliasKey: string; canonicalKey: string }> = [];\n const conflicts: EnvAliasConflict[] = [];\n\n for (const [aliasKey, canonicalKey] of Object.entries(aliasToCanonical)) {\n const aliasValue = env[aliasKey];\n if (aliasValue === undefined || aliasValue === \"\") continue;\n\n const canonicalValue = env[canonicalKey];\n if (canonicalValue === undefined || canonicalValue === \"\") {\n out[canonicalKey] = aliasValue;\n applied.push({ aliasKey, canonicalKey });\n continue;\n }\n\n if (canonicalValue !== aliasValue) {\n conflicts.push({\n canonicalKey,\n aliasKey,\n canonicalValue,\n aliasValue,\n });\n }\n }\n\n return { env: out, applied, conflicts };\n}\n","/**\n * Config Path API errors - implements Fulmen Config Path Standard error handling\n */\n\n/**\n * Base error class for config path operations\n */\nexport class ConfigPathError extends Error {\n constructor(\n message: string,\n public cause?: Error,\n ) {\n super(message);\n this.name = \"ConfigPathError\";\n\n // Maintains proper stack trace for where our error was thrown (only available on V8)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, ConfigPathError);\n }\n }\n\n /**\n * Create error for invalid application identifier\n */\n static invalidAppIdentifier(identifier: unknown): ConfigPathError {\n return new ConfigPathError(\n `Invalid application identifier: ${JSON.stringify(identifier)}. Expected { vendor: string, app: string }`,\n );\n }\n\n /**\n * Create error for invalid vendor/app names\n */\n static invalidName(name: string, type: \"vendor\" | \"app\"): ConfigPathError {\n return new ConfigPathError(\n `Invalid ${type} name: \"${name}\". Must be lowercase kebab-case (e.g., 'fulmenhq', 'my-app')`,\n );\n }\n\n /**\n * Create error for home directory detection failure\n */\n static homeDirNotFound(): ConfigPathError {\n return new ConfigPathError(\n \"Unable to determine home directory. Please set HOME environment variable.\",\n );\n }\n\n /**\n * Create error for directory creation failure\n */\n static directoryCreationFailed(path: string, cause: Error): ConfigPathError {\n return new ConfigPathError(`Failed to create directory: ${path}`, cause);\n }\n\n /**\n * Create error for invalid environment variable\n */\n static invalidEnvVar(varName: string, value: string): ConfigPathError {\n return new ConfigPathError(\n `Invalid environment variable ${varName}: ${value}. Path must be absolute and within user home directory.`,\n );\n }\n}\n\n/**\n * Error thrown when configuration validation fails\n */\nexport class ConfigValidationError extends Error {\n constructor(\n message: string,\n public diagnostics?: unknown[],\n public cause?: Error,\n ) {\n super(message);\n this.name = \"ConfigValidationError\";\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, ConfigValidationError);\n }\n }\n}\n","import { readFile } from \"node:fs/promises\";\nimport { extname } from \"node:path\";\nimport { parse } from \"yaml\";\nimport { compileSchema, validateData } from \"../schema/index.js\";\nimport { ConfigValidationError } from \"./errors.js\";\nimport { getConfigSearchPaths, resolveConfigPath } from \"./paths.js\";\nimport type { AppIdentifier } from \"./types.js\";\n\n/**\n * Options for loading configuration\n */\nexport interface LoadConfigOptions {\n /**\n * Application identifier for resolving user config paths\n */\n identity: AppIdentifier;\n\n /**\n * Absolute path to the defaults configuration file\n * This file MUST exist\n */\n defaultsPath: string;\n\n /**\n * Optional absolute path to a schema file for validation\n */\n schemaPath?: string;\n\n /**\n * Optional environment variable prefix for overrides\n * Defaults to identity.app.env_prefix if available, otherwise identity.app upper-cased\n */\n envPrefix?: string;\n\n /**\n * Optional override for the user config filename (excluding extension)\n * Defaults to identity.app.config_name or identity.app\n */\n userConfigName?: string;\n\n /**\n * Include env var consumption metadata for diagnostics.\n *\n * When enabled, loadConfig() records which environment variable keys were\n * consumed for prefix-based overrides.\n */\n includeEnvVarReport?: boolean;\n}\n\n/**\n * Metadata about the loaded configuration\n */\nexport interface ConfigMetadata {\n /**\n * Path to the defaults file used\n */\n defaultsPath: string;\n\n /**\n * Path to the user config file used (null if not found)\n */\n userConfigPath: string | null;\n\n /**\n * Environment variable prefix used for overrides\n */\n envPrefix: string;\n\n /**\n * Environment variable keys consumed (only when includeEnvVarReport is enabled)\n */\n envVarsConsumed?: string[];\n\n /**\n * Count of environment variable keys consumed (only when includeEnvVarReport is enabled)\n */\n envVarsConsumedCount?: number;\n\n /**\n * List of active configuration layers (\"defaults\", \"user\", \"env\")\n */\n activeLayers: string[];\n\n /**\n * Schema validation information\n */\n schema: {\n /**\n * Path to the schema file used (if any)\n */\n path: string | null;\n /**\n * Whether validation was performed\n */\n validated: boolean;\n };\n}\n\n/**\n * Result of a configuration load operation\n */\nexport interface LoadedConfig<T> {\n /**\n * The merged configuration object\n */\n config: T;\n\n /**\n * Metadata about the loading process\n */\n metadata: ConfigMetadata;\n}\n\n/**\n * Deep merge two objects.\n * - Arrays are replaced, not merged.\n * - Objects are merged recursively.\n * - primitives are replaced.\n */\n// biome-ignore lint/suspicious/noExplicitAny: Deep merge util handles arbitrary config objects\nfunction deepMerge(target: any, source: any): any {\n if (typeof source !== \"object\" || source === null) {\n return source;\n }\n\n if (Array.isArray(source)) {\n return structuredClone(source);\n }\n\n if (typeof target !== \"object\" || target === null || Array.isArray(target)) {\n return structuredClone(source);\n }\n\n const output = { ...target };\n\n for (const key of Object.keys(source)) {\n if (Object.hasOwn(source, key)) {\n if (key in target) {\n output[key] = deepMerge(target[key], source[key]);\n } else {\n output[key] = structuredClone(source[key]);\n }\n }\n }\n\n return output;\n}\n\n/**\n * Parse a value from an environment variable string\n */\n// biome-ignore lint/suspicious/noExplicitAny: Return type depends on parsing result (string, number, bool, object)\nfunction parseEnvValue(value: string): any {\n // Boolean\n if (value.toLowerCase() === \"true\") return true;\n if (value.toLowerCase() === \"false\") return false;\n\n // Number\n if (!Number.isNaN(Number(value)) && value.trim() !== \"\") {\n return Number(value);\n }\n\n // JSON (e.g. array or object)\n try {\n const parsed = JSON.parse(value);\n if (typeof parsed === \"object\" || Array.isArray(parsed)) {\n return parsed;\n }\n } catch {\n // Ignore JSON parse errors, treat as string\n }\n\n return value;\n}\n\n/**\n * Parse environment variables into a config object\n */\n// biome-ignore lint/suspicious/noExplicitAny: Config object is dynamically constructed\nfunction parseEnvVars(prefix: string): any {\n // biome-ignore lint/suspicious/noExplicitAny: Config object is dynamically constructed\n const config: any = {};\n const prefixWithSeparator = `${prefix}_`;\n\n for (const [key, value] of Object.entries(process.env)) {\n if (!value) continue;\n\n if (key.startsWith(prefixWithSeparator)) {\n const keyWithoutPrefix = key.slice(prefixWithSeparator.length);\n const parts = keyWithoutPrefix.split(\"_\").filter((p) => p.length > 0);\n\n let current = config;\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i].toLowerCase();\n\n // If it's the last part, set the value\n if (i === parts.length - 1) {\n current[part] = parseEnvValue(value);\n } else {\n // Create nested object if it doesn't exist\n if (!current[part] || typeof current[part] !== \"object\") {\n current[part] = {};\n }\n current = current[part];\n }\n }\n }\n }\n\n return config;\n}\n\n/**\n * Parse environment variables into a config object (with consumption report)\n */\nfunction parseEnvVarsWithReport(prefix: string): {\n config: unknown;\n consumedKeys: string[];\n} {\n // biome-ignore lint/suspicious/noExplicitAny: Config object is dynamically constructed\n const config: any = {};\n const consumedKeys: string[] = [];\n const prefixWithSeparator = `${prefix}_`;\n\n for (const [key, value] of Object.entries(process.env)) {\n if (!value) continue;\n\n if (key.startsWith(prefixWithSeparator)) {\n consumedKeys.push(key);\n\n const keyWithoutPrefix = key.slice(prefixWithSeparator.length);\n const parts = keyWithoutPrefix.split(\"_\").filter((p) => p.length > 0);\n\n let current = config;\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i].toLowerCase();\n\n if (i === parts.length - 1) {\n current[part] = parseEnvValue(value);\n } else {\n if (!current[part] || typeof current[part] !== \"object\") {\n current[part] = {};\n }\n current = current[part];\n }\n }\n }\n }\n\n consumedKeys.sort();\n return { config, consumedKeys };\n}\n\n/**\n * Parse a configuration file based on its extension\n */\n// biome-ignore lint/suspicious/noExplicitAny: Parsed config is untyped\nasync function parseConfigFile(path: string): Promise<any> {\n const content = await readFile(path, \"utf-8\");\n const ext = extname(path).toLowerCase();\n\n if (ext === \".json\") {\n return JSON.parse(content);\n }\n\n if (ext === \".yaml\" || ext === \".yml\") {\n return parse(content);\n }\n\n throw new Error(`Unsupported config file extension: ${ext}`);\n}\n\n/**\n * Load configuration using the Three-Layer pattern:\n * 1. Defaults (required)\n * 2. User Config (optional, XDG-compliant)\n * 3. Environment Variables (optional, prefix-based)\n */\nexport async function loadConfig<T>(options: LoadConfigOptions): Promise<LoadedConfig<T>> {\n const { identity, defaultsPath, userConfigName } = options;\n const activeLayers: string[] = [\"defaults\"];\n\n // Layer 1: Defaults\n let mergedConfig = await parseConfigFile(defaultsPath);\n\n // Layer 2: User Config\n const configName = userConfigName || identity.app; // Simple fallback, assuming identity.app is suitable\n\n // We use resolveConfigPath which expects a filename and search paths.\n // But we support multiple extensions (.yaml, .yml, .json).\n // We iterate through extensions and try to find the file.\n\n const extensions = [\".yaml\", \".yml\", \".json\"];\n let userConfigPath: string | null = null;\n\n const paths = getConfigSearchPaths(identity);\n\n for (const ext of extensions) {\n const filename = `${configName}${ext}`;\n const foundPath = await resolveConfigPath(filename, paths);\n if (foundPath) {\n userConfigPath = foundPath;\n break;\n }\n }\n\n if (userConfigPath) {\n const userConfig = await parseConfigFile(userConfigPath);\n mergedConfig = deepMerge(mergedConfig, userConfig);\n activeLayers.push(\"user\");\n }\n\n // Phase 2: Env Overrides\n const envPrefix =\n options.envPrefix || (identity.app ? identity.app.toUpperCase().replace(/-/g, \"_\") : \"APP\");\n\n const includeEnvVarReport = options.includeEnvVarReport === true;\n const envVars = includeEnvVarReport ? parseEnvVarsWithReport(envPrefix) : null;\n const envConfig = includeEnvVarReport ? envVars?.config : parseEnvVars(envPrefix);\n\n if (\n envConfig &&\n typeof envConfig === \"object\" &&\n Object.keys(envConfig as Record<string, unknown>).length > 0\n ) {\n mergedConfig = deepMerge(mergedConfig, envConfig);\n activeLayers.push(\"env\");\n }\n\n // Phase 3: Validation\n if (options.schemaPath) {\n try {\n const schemaContent = await readFile(options.schemaPath, \"utf-8\");\n const validator = await compileSchema(schemaContent);\n const result = validateData(mergedConfig, validator);\n\n if (!result.valid) {\n throw new ConfigValidationError(\"Configuration validation failed\", result.diagnostics);\n }\n\n // We modify the metadata object that will be returned\n // (Since we return a new object literal below, we just set the property in the return statement)\n } catch (error) {\n if (error instanceof ConfigValidationError) {\n throw error;\n }\n throw new ConfigValidationError(\n `Failed to validate configuration: ${(error as Error).message}`,\n undefined,\n error as Error,\n );\n }\n }\n\n return {\n config: mergedConfig as T,\n metadata: {\n defaultsPath,\n userConfigPath,\n envPrefix,\n envVarsConsumed: includeEnvVarReport ? envVars?.consumedKeys : undefined,\n envVarsConsumedCount: includeEnvVarReport ? envVars?.consumedKeys.length : undefined,\n activeLayers,\n schema: {\n path: options.schemaPath || null,\n validated: !!options.schemaPath,\n },\n },\n };\n}\n","/**\n * Config Path API - implements Fulmen Config Path Standard\n *\n * Provides cross-platform directory resolution for Fulmen configuration, data, and cache directories\n * with XDG Base Directory specification compliance.\n */\n\nimport { access, mkdir } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { isAbsolute, join, resolve } from \"node:path\";\nimport { metrics } from \"../telemetry/index.js\";\nimport { ConfigPathError } from \"./errors.js\";\nimport type { AppIdentifier, ConfigPathOptions, PlatformDirs, XDGBaseDirs } from \"./types.js\";\n\n/**\n * Get platform information and environment variables\n */\nfunction getPlatformInfo(): PlatformDirs {\n const osPlatform = process.platform;\n const homeDir = homedir();\n\n if (!homeDir) {\n throw ConfigPathError.homeDirNotFound();\n }\n\n const platformInfo: PlatformDirs = {\n platform:\n osPlatform === \"linux\"\n ? \"linux\"\n : osPlatform === \"darwin\"\n ? \"darwin\"\n : osPlatform === \"win32\"\n ? \"win32\"\n : \"unknown\",\n homeDir,\n };\n\n // XDG environment variables (Linux/Unix)\n if (osPlatform === \"linux\") {\n platformInfo.xdgEnv = {\n XDG_CONFIG_HOME: process.env.XDG_CONFIG_HOME,\n XDG_DATA_HOME: process.env.XDG_DATA_HOME,\n XDG_CACHE_HOME: process.env.XDG_CACHE_HOME,\n };\n }\n\n // Windows environment variables\n if (osPlatform === \"win32\") {\n platformInfo.winEnv = {\n APPDATA: process.env.APPDATA,\n LOCALAPPDATA: process.env.LOCALAPPDATA,\n };\n }\n\n return platformInfo;\n}\n\n/**\n * Validate vendor and app names according to kebab-case convention\n */\nfunction validateKebabCase(name: string, type: \"vendor\" | \"app\"): void {\n if (!name || typeof name !== \"string\") {\n throw ConfigPathError.invalidName(name, type);\n }\n\n // Must be lowercase and contain only letters, numbers, and hyphens\n if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(name)) {\n throw ConfigPathError.invalidName(name, type);\n }\n}\n\n/**\n * Validate application identifier\n */\nfunction validateAppIdentifier(app: AppIdentifier): void {\n if (!app || typeof app !== \"object\") {\n throw ConfigPathError.invalidAppIdentifier(app);\n }\n\n if (!app.vendor || !app.app) {\n throw ConfigPathError.invalidAppIdentifier(app);\n }\n\n validateKebabCase(app.vendor, \"vendor\");\n validateKebabCase(app.app, \"app\");\n}\n\n/**\n * Validate environment variable override path\n */\nfunction validateEnvVarPath(path: string, varName: string, homeDir: string): void {\n if (!isAbsolute(path)) {\n throw ConfigPathError.invalidEnvVar(varName, path);\n }\n\n // Security: ensure path is within home directory unless explicitly allowed\n // Normalize paths for case-insensitive comparison on Windows\n const resolvedPath = resolve(path);\n const resolvedHome = resolve(homeDir);\n\n // Case-insensitive comparison for Windows, case-sensitive for Unix-like systems\n const isWindows = process.platform === \"win32\";\n const normalizedPath = isWindows ? resolvedPath.toLowerCase() : resolvedPath;\n const normalizedHome = isWindows ? resolvedHome.toLowerCase() : resolvedHome;\n\n if (!normalizedPath.startsWith(normalizedHome)) {\n throw ConfigPathError.invalidEnvVar(varName, path);\n }\n}\n\n/**\n * Get XDG base directories with environment variable overrides\n */\nexport function getXDGBaseDirs(options: ConfigPathOptions = {}): XDGBaseDirs {\n const platformInfo = getPlatformInfo();\n const homeDir = options.customHomeDir || platformInfo.homeDir;\n\n // Environment variable overrides take precedence\n const configHome =\n process.env.FULMEN_CONFIG_HOME || process.env.XDG_CONFIG_HOME || join(homeDir, \".config\");\n\n const dataHome =\n process.env.FULMEN_DATA_HOME || process.env.XDG_DATA_HOME || join(homeDir, \".local\", \"share\");\n\n const cacheHome =\n process.env.FULMEN_CACHE_HOME || process.env.XDG_CACHE_HOME || join(homeDir, \".cache\");\n\n // Validate environment variable overrides\n if (process.env.FULMEN_CONFIG_HOME) {\n validateEnvVarPath(configHome, \"FULMEN_CONFIG_HOME\", homeDir);\n }\n if (process.env.FULMEN_DATA_HOME) {\n validateEnvVarPath(dataHome, \"FULMEN_DATA_HOME\", homeDir);\n }\n if (process.env.FULMEN_CACHE_HOME) {\n validateEnvVarPath(cacheHome, \"FULMEN_CACHE_HOME\", homeDir);\n }\n\n return {\n configHome,\n dataHome,\n cacheHome,\n };\n}\n\n/**\n * Get platform-specific base directories\n */\nfunction getPlatformBaseDirs(options: ConfigPathOptions = {}): XDGBaseDirs {\n const platformInfo = getPlatformInfo();\n const homeDir = options.customHomeDir || platformInfo.homeDir;\n\n switch (platformInfo.platform) {\n case \"darwin\": {\n // macOS: ~/Library/Application Support for config and data\n const appSupport = join(homeDir, \"Library\", \"Application Support\");\n const cacheSupport = join(homeDir, \"Library\", \"Caches\");\n\n // Start with platform defaults\n let configHome = appSupport;\n let dataHome = appSupport;\n let cacheHome = cacheSupport;\n\n // Apply environment variable overrides with validation\n if (process.env.FULMEN_CONFIG_HOME) {\n validateEnvVarPath(process.env.FULMEN_CONFIG_HOME, \"FULMEN_CONFIG_HOME\", homeDir);\n configHome = process.env.FULMEN_CONFIG_HOME;\n }\n if (process.env.FULMEN_DATA_HOME) {\n validateEnvVarPath(process.env.FULMEN_DATA_HOME, \"FULMEN_DATA_HOME\", homeDir);\n dataHome = process.env.FULMEN_DATA_HOME;\n }\n if (process.env.FULMEN_CACHE_HOME) {\n validateEnvVarPath(process.env.FULMEN_CACHE_HOME, \"FULMEN_CACHE_HOME\", homeDir);\n cacheHome = process.env.FULMEN_CACHE_HOME;\n }\n\n return { configHome, dataHome, cacheHome };\n }\n\n case \"win32\": {\n // Windows: %APPDATA% for config, %LOCALAPPDATA% for data and cache\n const appData = platformInfo.winEnv?.APPDATA || join(homeDir, \"AppData\", \"Roaming\");\n const localAppData = platformInfo.winEnv?.LOCALAPPDATA || join(homeDir, \"AppData\", \"Local\");\n const cacheDir = join(localAppData, \"Cache\");\n\n // Start with platform defaults\n let configHome = appData;\n let dataHome = localAppData;\n let cacheHome = cacheDir;\n\n // Apply environment variable overrides with validation\n if (process.env.FULMEN_CONFIG_HOME) {\n validateEnvVarPath(process.env.FULMEN_CONFIG_HOME, \"FULMEN_CONFIG_HOME\", homeDir);\n configHome = process.env.FULMEN_CONFIG_HOME;\n }\n if (process.env.FULMEN_DATA_HOME) {\n validateEnvVarPath(process.env.FULMEN_DATA_HOME, \"FULMEN_DATA_HOME\", homeDir);\n dataHome = process.env.FULMEN_DATA_HOME;\n }\n if (process.env.FULMEN_CACHE_HOME) {\n validateEnvVarPath(process.env.FULMEN_CACHE_HOME, \"FULMEN_CACHE_HOME\", homeDir);\n cacheHome = process.env.FULMEN_CACHE_HOME;\n }\n\n return { configHome, dataHome, cacheHome };\n }\n\n case \"linux\":\n // Linux: use XDG (already includes validation)\n return getXDGBaseDirs(options);\n\n default:\n // Fallback: use XDG (Linux-style, already includes validation)\n return getXDGBaseDirs(options);\n }\n}\n\n/**\n * Get Fulmen-specific config directory\n */\nexport function getFulmenConfigDir(options: ConfigPathOptions = {}): string {\n const baseDirs = getPlatformBaseDirs(options);\n return join(baseDirs.configHome, \"fulmen\");\n}\n\n/**\n * Get Fulmen-specific data directory\n */\nexport function getFulmenDataDir(options: ConfigPathOptions = {}): string {\n const baseDirs = getPlatformBaseDirs(options);\n return join(baseDirs.dataHome, \"fulmen\");\n}\n\n/**\n * Get Fulmen-specific cache directory\n */\nexport function getFulmenCacheDir(options: ConfigPathOptions = {}): string {\n const baseDirs = getPlatformBaseDirs(options);\n return join(baseDirs.cacheHome, \"fulmen\");\n}\n\n/**\n * Get application-specific config directory\n */\nexport function getAppConfigDir(app: AppIdentifier, options: ConfigPathOptions = {}): string {\n validateAppIdentifier(app);\n const fulmenConfig = getFulmenConfigDir(options);\n return join(fulmenConfig, app.vendor, app.app);\n}\n\n/**\n * Get application-specific data directory\n */\nexport function getAppDataDir(app: AppIdentifier, options: ConfigPathOptions = {}): string {\n validateAppIdentifier(app);\n const fulmenData = getFulmenDataDir(options);\n return join(fulmenData, app.vendor, app.app);\n}\n\n/**\n * Get application-specific cache directory\n */\nexport function getAppCacheDir(app: AppIdentifier, options: ConfigPathOptions = {}): string {\n validateAppIdentifier(app);\n const fulmenCache = getFulmenCacheDir(options);\n return join(fulmenCache, app.vendor, app.app);\n}\n\n/**\n * Get ordered list of config search paths for an application\n */\nexport function getConfigSearchPaths(\n app: AppIdentifier,\n options: ConfigPathOptions = {},\n): string[] {\n validateAppIdentifier(app);\n\n const paths: string[] = [];\n\n // 1. Application-specific config directory (highest priority)\n paths.push(getAppConfigDir(app, options));\n\n // 2. Fulmen-wide config directory\n paths.push(getFulmenConfigDir(options));\n\n // 3. Legacy names for migration support\n if (options.legacyNames) {\n for (const legacyName of options.legacyNames) {\n const baseDirs = getPlatformBaseDirs(options);\n paths.push(join(baseDirs.configHome, legacyName));\n }\n }\n\n return paths;\n}\n\n/**\n * Ensure directory exists (create if necessary)\n */\nexport async function ensureDirExists(dirPath: string): Promise<void> {\n const startTime = performance.now();\n\n try {\n await access(dirPath);\n metrics.histogram(\"config_load_ms\").observe(performance.now() - startTime);\n } catch (error) {\n const nodeError = error as NodeJS.ErrnoException;\n if (nodeError.code === \"ENOENT\") {\n try {\n await mkdir(dirPath, { recursive: true });\n metrics.histogram(\"config_load_ms\").observe(performance.now() - startTime);\n } catch (mkdirError) {\n metrics.counter(\"config_load_errors\").inc();\n metrics.histogram(\"config_load_ms\").observe(performance.now() - startTime);\n throw ConfigPathError.directoryCreationFailed(dirPath, mkdirError as Error);\n }\n } else {\n metrics.counter(\"config_load_errors\").inc();\n metrics.histogram(\"config_load_ms\").observe(performance.now() - startTime);\n throw ConfigPathError.directoryCreationFailed(dirPath, nodeError);\n }\n }\n}\n\n/**\n * Resolve config file path with search path logic\n */\nexport async function resolveConfigPath(\n filename: string,\n searchPaths: string[],\n options: { ensureDir?: boolean } = {},\n): Promise<string | null> {\n const startTime = performance.now();\n\n try {\n for (const searchPath of searchPaths) {\n if (options.ensureDir) {\n await ensureDirExists(searchPath);\n }\n\n const fullPath = join(searchPath, filename);\n try {\n await access(fullPath);\n metrics.histogram(\"config_load_ms\").observe(performance.now() - startTime);\n return fullPath;\n } catch (error) {\n const nodeError = error as NodeJS.ErrnoException;\n if (nodeError.code !== \"ENOENT\") {\n metrics.counter(\"config_load_errors\").inc();\n metrics.histogram(\"config_load_ms\").observe(performance.now() - startTime);\n throw error;\n }\n }\n }\n\n metrics.histogram(\"config_load_ms\").observe(performance.now() - startTime);\n return null;\n } catch (error) {\n if (!(error instanceof ConfigPathError)) {\n metrics.counter(\"config_load_errors\").inc();\n metrics.histogram(\"config_load_ms\").observe(performance.now() - startTime);\n }\n throw error;\n }\n}\n","/**\n * Config module - implements Fulmen Config Path Standard\n *\n * Provides utilities for config path resolution and three-layer config loading\n */\n\nexport const VERSION = \"0.1.0\";\n\nexport * from \"./env-alias.js\";\nexport * from \"./errors.js\";\nexport * from \"./loader.js\";\n// Config Path API exports\nexport * from \"./paths.js\";\nexport * from \"./types.js\";\n"]}
1
+ {"version":3,"sources":["../../src/schema/ajv-formats.ts","../../src/schema/errors.ts","../../src/schema/utils.ts","../../src/schema/goneat-bridge.ts","../../src/schema/normalizer.ts","../../src/schema/registry.ts","../../src/telemetry/counter.ts","../../src/telemetry/gauge.ts","../../src/telemetry/taxonomy.ts","../../src/telemetry/histogram.ts","../../src/telemetry/registry.ts","../../src/telemetry/types.ts","../../src/telemetry/validators.ts","../../src/telemetry/index.ts","../../src/schema/validator.ts","../../src/schema/cli.ts","../../src/schema/export.ts","../../src/schema/index.ts","../../src/config/env-alias.ts","../../src/config/errors.ts","../../src/config/loader.ts","../../src/config/paths.ts","../../src/config/index.ts"],"names":["join","readFile","parseYaml","init_registry","fileURLToPath","__dirname","dirname","parseYAML","access","mkdir","extname"],"mappings":";;;;;;;;;;;;;;;;;;AAyBO,SAAS,qBAAA,CAAsB,GAAA,EAAU,OAAA,GAAmC,EAAC,EAAQ;AAC1F,EAAA,MAAM,IAAA,GAAO,QAAQ,IAAA,IAAQ,MAAA;AAC7B,EAAA,MAAM,OAAA,GAAU,QAAQ,OAAA,IAAW,eAAA;AAKnC,EAAA,UAAA,CAAW,GAAA,EAAc,EAAE,IAAA,EAAM,OAAA,EAAwC,CAAA;AACzE,EAAA,OAAO,GAAA;AACT;AAlCA,IAQM,eAAA;AARN,IAAA,gBAAA,GAAA,KAAA,CAAA;AAAA,EAAA,2BAAA,GAAA;AAQA,IAAM,eAAA,GAAkB;AAAA,MACtB,WAAA;AAAA,MACA,OAAA;AAAA,MACA,UAAA;AAAA,MACA,MAAA;AAAA,MACA,MAAA;AAAA,MACA,KAAA;AAAA,MACA,eAAA;AAAA,MACA;AAAA,KACF;AAAA,EAAA;AAAA,CAAA,CAAA;;;ACjBA,IAoBa,qBAAA;AApBb,IAAA,WAAA,GAAA,KAAA,CAAA;AAAA,EAAA,sBAAA,GAAA;AAoBO,IAAM,qBAAA,GAAN,MAAM,sBAAA,SAA8B,KAAA,CAAM;AAAA,MAC/C,YACE,OAAA,EACO,QAAA,EACA,cAA4C,EAAC,EAC7C,QACA,KAAA,EACP;AACA,QAAA,KAAA,CAAM,OAAO,CAAA;AALN,QAAA,IAAA,CAAA,QAAA,GAAA,QAAA;AACA,QAAA,IAAA,CAAA,WAAA,GAAA,WAAA;AACA,QAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AACA,QAAA,IAAA,CAAA,KAAA,GAAA,KAAA;AAGP,QAAA,IAAA,CAAK,IAAA,GAAO,uBAAA;AAGZ,QAAA,IAAI,MAAM,iBAAA,EAAmB;AAC3B,UAAA,KAAA,CAAM,iBAAA,CAAkB,MAAM,sBAAqB,CAAA;AAAA,QACrD;AAAA,MACF;AAAA;AAAA;AAAA;AAAA,MAKA,OAAO,eAAe,QAAA,EAAyC;AAC7D,QAAA,OAAO,IAAI,sBAAA,CAAsB,CAAA,kBAAA,EAAqB,QAAQ,IAAI,QAAQ,CAAA;AAAA,MAC5E;AAAA;AAAA;AAAA;AAAA,MAKA,OAAO,kBAAA,CAAmB,MAAA,EAAsB,OAAA,EAAwC;AACtF,QAAA,OAAO,IAAI,uBAAsB,CAAA,sBAAA,EAAyB,OAAO,IAAI,MAAA,EAAW,IAAI,MAAM,CAAA;AAAA,MAC5F;AAAA;AAAA;AAAA;AAAA,MAKA,OAAO,gBAAA,CACL,QAAA,EACA,WAAA,EACA,MAAA,EACuB;AACvB,QAAA,MAAM,UAAA,GAAa,YAAY,MAAA,CAAO,CAAC,MAAM,CAAA,CAAE,QAAA,KAAa,OAAO,CAAA,CAAE,MAAA;AACrE,QAAA,MAAM,YAAA,GAAe,YAAY,MAAA,CAAO,CAAC,MAAM,CAAA,CAAE,QAAA,KAAa,MAAM,CAAA,CAAE,MAAA;AAEtE,QAAA,MAAM,OAAA,GAAU,CAAA,0BAAA,EAA6B,UAAU,CAAA,WAAA,EAAc,YAAY,CAAA,WAAA,CAAA;AAEjF,QAAA,OAAO,IAAI,sBAAA,CAAsB,OAAA,EAAS,QAAA,EAAU,aAAa,MAAM,CAAA;AAAA,MACzE;AAAA;AAAA;AAAA;AAAA,MAKA,OAAO,eAAe,UAAA,EAA4C;AAChE,QAAA,MAAM,QAAA,GAAW,UAAA,GAAa,CAAA,IAAA,EAAO,UAAU,CAAA,CAAA,GAAK,EAAA;AACpD,QAAA,OAAO,IAAI,sBAAA;AAAA,UACT,0BAA0B,QAAQ,CAAA,iCAAA;AAAA,SACpC;AAAA,MACF;AAAA;AAAA;AAAA;AAAA,MAKA,OAAO,sBAAsB,KAAA,EAAqC;AAChE,QAAA,OAAO,IAAI,sBAAA;AAAA,UACT,0DAAA;AAAA,UACA,MAAA;AAAA,UACA,EAAC;AAAA,UACD,MAAA;AAAA,UACA;AAAA,SACF;AAAA,MACF;AAAA;AAAA;AAAA;AAAA,MAKA,OAAO,iBAAiB,MAAA,EAA8C;AACpE,QAAA,OAAO,IAAI,sBAAA,CAAsB,yBAAA,EAA2B,MAAA,EAAW,IAAI,MAAM,CAAA;AAAA,MACnF;AAAA;AAAA;AAAA;AAAA,MAKA,OAAO,WAAA,CAAY,MAAA,EAAsB,KAAA,EAAqC;AAC5E,QAAA,OAAO,IAAI,sBAAA;AAAA,UACT,CAAA,wBAAA,EAA2B,MAAM,OAAO,CAAA,CAAA;AAAA,UACxC,MAAA;AAAA,UACA,EAAC;AAAA,UACD,MAAA;AAAA,UACA;AAAA,SACF;AAAA,MACF;AAAA;AAAA;AAAA;AAAA,MAKA,OAAO,cAAA,CAAe,MAAA,EAAsB,KAAA,EAAqC;AAC/E,QAAA,OAAO,IAAI,sBAAA;AAAA,UACT,CAAA,yBAAA,EAA4B,MAAM,OAAO,CAAA,CAAA;AAAA,UACzC,MAAA;AAAA,UACA,EAAC;AAAA,UACD,MAAA;AAAA,UACA;AAAA,SACF;AAAA,MACF;AAAA;AAAA;AAAA;AAAA,MAKA,OAAO,aAAA,CAAc,SAAA,EAAmB,OAAA,EAAwC;AAC9E,QAAA,OAAO,IAAI,sBAAA,CAAsB,CAAA,gBAAA,EAAmB,SAAS,CAAA,SAAA,EAAY,OAAO,CAAA,CAAE,CAAA;AAAA,MACpF;AAAA;AAAA;AAAA;AAAA,MAKA,MAAA,GAAiB;AACf,QAAA,IAAI,SAAS,IAAA,CAAK,OAAA;AAElB,QAAA,IAAI,KAAK,QAAA,EAAU;AACjB,UAAA,MAAA,IAAU;AAAA,WAAA,EAAgB,KAAK,QAAQ,CAAA,CAAA;AAAA,QACzC;AAEA,QAAA,IAAI,IAAA,CAAK,WAAA,CAAY,MAAA,GAAS,CAAA,EAAG;AAC/B,UAAA,MAAA,IAAU,wBAAA;AACV,UAAA,IAAA,CAAK,WAAA,CAAY,OAAA,CAAQ,CAAC,IAAA,EAAM,KAAA,KAAU;AACxC,YAAA,MAAA,IAAU;AAAA,EAAA,EAAO,QAAQ,CAAC,CAAA,GAAA,EAAM,KAAK,QAAQ,CAAA,EAAA,EAAK,KAAK,OAAO,CAAA,CAAA;AAC9D,YAAA,IAAI,KAAK,OAAA,EAAS;AAChB,cAAA,MAAA,IAAU,CAAA,IAAA,EAAO,KAAK,OAAO,CAAA,CAAA;AAAA,YAC/B;AACA,YAAA,IAAI,KAAK,OAAA,EAAS;AAChB,cAAA,MAAA,IAAU,CAAA,WAAA,EAAc,KAAK,OAAO,CAAA,CAAA,CAAA;AAAA,YACtC;AACA,YAAA,IAAI,KAAK,MAAA,EAAQ;AACf,cAAA,MAAA,IAAU,CAAA,EAAA,EAAK,KAAK,MAAM,CAAA,CAAA,CAAA;AAAA,YAC5B;AAAA,UACF,CAAC,CAAA;AAAA,QACH;AAEA,QAAA,IAAI,KAAK,MAAA,EAAQ;AACf,UAAA,MAAA,IAAU;;AAAA,QAAA,EAAe,IAAA,CAAK,OAAO,IAAI,CAAA,CAAA;AACzC,UAAA,IAAI,IAAA,CAAK,OAAO,EAAA,EAAI;AAClB,YAAA,MAAA,IAAU,CAAA,EAAA,EAAK,IAAA,CAAK,MAAA,CAAO,EAAE,CAAA,CAAA,CAAA;AAAA,UAC/B;AAAA,QACF;AAEA,QAAA,OAAO,MAAA;AAAA,MACT;AAAA;AAAA;AAAA;AAAA,MAKA,MAAA,GAOE;AACA,QAAA,OAAO;AAAA,UACL,MAAM,IAAA,CAAK,IAAA;AAAA,UACX,SAAS,IAAA,CAAK,OAAA;AAAA,UACd,UAAU,IAAA,CAAK,QAAA;AAAA,UACf,aAAa,IAAA,CAAK,WAAA;AAAA,UAClB,QAAQ,IAAA,CAAK,MAAA;AAAA,UACb,KAAA,EAAO,KAAK,KAAA,EAAO;AAAA,SACrB;AAAA,MACF;AAAA,KACF;AAAA,EAAA;AAAA,CAAA,CAAA;;;ACjFO,SAAS,gBAAA,CACd,SACA,OAAA,EACA,OAAA,EACA,WAA6B,OAAA,EAC7B,MAAA,GAA2B,OAC3B,IAAA,EAC4B;AAC5B,EAAA,OAAO;AAAA,IACL,OAAA;AAAA,IACA,OAAA;AAAA,IACA,OAAA;AAAA,IACA,QAAA;AAAA,IACA,MAAA;AAAA,IACA;AAAA,GACF;AACF;AAzHA,IAAA,UAAA,GAAA,KAAA,CAAA;AAAA,EAAA,qBAAA,GAAA;AAIA,IAAA,WAAA,EAAA;AAAA,EAAA;AAAA,CAAA,CAAA;ACJA,IAAA,kBAAA,GAAA,KAAA,CAAA;AAAA,EAAA,6BAAA,GAAA;AAUA,IAAA,UAAA,EAAA;AAAA,EAAA;AAAA,CAAA,CAAA;ACVA,IAAA,eAAA,GAAA,KAAA,CAAA;AAAA,EAAA,0BAAA,GAAA;AAQA,IAAA,WAAA,EAAA;AAAA,EAAA;AAAA,CAAA,CAAA;ACRA,IAAA,aAAA,GAAA,KAAA,CAAA;AAAA,EAAA,wBAAA,GAAA;AASA,IAAA,WAAA,EAAA;AAAA,EAAA;AAAA,CAAA,CAAA;;;ACTA,IAea,OAAA;AAfb,IAAA,YAAA,GAAA,KAAA,CAAA;AAAA,EAAA,0BAAA,GAAA;AAeO,IAAM,UAAN,MAAc;AAAA,MAInB,YAA4B,IAAA,EAAkB;AAAlB,QAAA,IAAA,CAAA,IAAA,GAAA,IAAA;AAAA,MAAmB;AAAA,MAHvC,KAAA,GAAQ,CAAA;AAAA,MACR,aAAA,uBAAoB,GAAA,EAAoB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAmBhD,GAAA,CAAI,KAAA,GAAQ,CAAA,EAAG,MAAA,EAAuC;AACpD,QAAA,IAAI,QAAQ,CAAA,EAAG;AACb,UAAA,MAAM,IAAI,KAAA,CAAM,CAAA,yCAAA,EAA4C,KAAK,CAAA,CAAE,CAAA;AAAA,QACrE;AAEA,QAAA,IAAI,UAAU,MAAA,CAAO,IAAA,CAAK,MAAM,CAAA,CAAE,SAAS,CAAA,EAAG;AAE5C,UAAA,MAAM,QAAA,GAAW,IAAA,CAAK,eAAA,CAAgB,MAAM,CAAA;AAC5C,UAAA,MAAM,OAAA,GAAU,IAAA,CAAK,aAAA,CAAc,GAAA,CAAI,QAAQ,CAAA,IAAK,CAAA;AACpD,UAAA,IAAA,CAAK,aAAA,CAAc,GAAA,CAAI,QAAA,EAAU,OAAA,GAAU,KAAK,CAAA;AAAA,QAClD,CAAA,MAAO;AAEL,UAAA,IAAA,CAAK,KAAA,IAAS,KAAA;AAAA,QAChB;AAAA,MACF;AAAA;AAAA;AAAA;AAAA,MAKA,QAAA,GAAmB;AACjB,QAAA,OAAO,IAAA,CAAK,KAAA;AAAA,MACd;AAAA;AAAA;AAAA;AAAA;AAAA,MAMA,gBAAA,GAAwC;AACtC,QAAA,OAAO,IAAI,GAAA,CAAI,IAAA,CAAK,aAAa,CAAA;AAAA,MACnC;AAAA;AAAA;AAAA;AAAA,MAKA,kBAAkB,MAAA,EAAwC;AACxD,QAAA,MAAM,QAAA,GAAW,IAAA,CAAK,eAAA,CAAgB,MAAM,CAAA;AAC5C,QAAA,OAAO,IAAA,CAAK,aAAA,CAAc,GAAA,CAAI,QAAQ,CAAA,IAAK,CAAA;AAAA,MAC7C;AAAA;AAAA;AAAA;AAAA,MAKA,KAAA,GAAc;AACZ,QAAA,IAAA,CAAK,KAAA,GAAQ,CAAA;AACb,QAAA,IAAA,CAAK,cAAc,KAAA,EAAM;AAAA,MAC3B;AAAA;AAAA;AAAA;AAAA;AAAA,MAMQ,gBAAgB,MAAA,EAAwC;AAC9D,QAAA,OAAO,MAAA,CAAO,OAAA,CAAQ,MAAM,CAAA,CACzB,IAAA,CAAK,CAAC,CAAC,CAAC,CAAA,EAAG,CAAC,CAAC,CAAA,KAAM,EAAE,aAAA,CAAc,CAAC,CAAC,CAAA,CACrC,GAAA,CAAI,CAAC,CAAC,CAAA,EAAG,CAAC,CAAA,KAAM,CAAA,EAAG,CAAC,CAAA,CAAA,EAAI,CAAC,CAAA,CAAE,CAAA,CAC3B,KAAK,GAAG,CAAA;AAAA,MACb;AAAA,KACF;AAAA,EAAA;AAAA,CAAA,CAAA;;;AC7FA,IAea,KAAA;AAfb,IAAA,UAAA,GAAA,KAAA,CAAA;AAAA,EAAA,wBAAA,GAAA;AAeO,IAAM,QAAN,MAAY;AAAA,MAIjB,YAA4B,IAAA,EAAkB;AAAlB,QAAA,IAAA,CAAA,IAAA,GAAA,IAAA;AAAA,MAAmB;AAAA,MAHvC,KAAA,GAAQ,CAAA;AAAA,MACR,aAAA,uBAAoB,GAAA,EAAoB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAiBhD,GAAA,CAAI,OAAe,MAAA,EAAuC;AACxD,QAAA,IAAI,UAAU,MAAA,CAAO,IAAA,CAAK,MAAM,CAAA,CAAE,SAAS,CAAA,EAAG;AAC5C,UAAA,MAAM,QAAA,GAAW,IAAA,CAAK,eAAA,CAAgB,MAAM,CAAA;AAC5C,UAAA,IAAA,CAAK,aAAA,CAAc,GAAA,CAAI,QAAA,EAAU,KAAK,CAAA;AAAA,QACxC,CAAA,MAAO;AACL,UAAA,IAAA,CAAK,KAAA,GAAQ,KAAA;AAAA,QACf;AAAA,MACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAQA,GAAA,CAAI,KAAA,GAAQ,CAAA,EAAG,MAAA,EAAuC;AACpD,QAAA,IAAI,UAAU,MAAA,CAAO,IAAA,CAAK,MAAM,CAAA,CAAE,SAAS,CAAA,EAAG;AAC5C,UAAA,MAAM,QAAA,GAAW,IAAA,CAAK,eAAA,CAAgB,MAAM,CAAA;AAC5C,UAAA,MAAM,OAAA,GAAU,IAAA,CAAK,aAAA,CAAc,GAAA,CAAI,QAAQ,CAAA,IAAK,CAAA;AACpD,UAAA,IAAA,CAAK,aAAA,CAAc,GAAA,CAAI,QAAA,EAAU,OAAA,GAAU,KAAK,CAAA;AAAA,QAClD,CAAA,MAAO;AACL,UAAA,IAAA,CAAK,KAAA,IAAS,KAAA;AAAA,QAChB;AAAA,MACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAQA,GAAA,CAAI,KAAA,GAAQ,CAAA,EAAG,MAAA,EAAuC;AACpD,QAAA,IAAI,UAAU,MAAA,CAAO,IAAA,CAAK,MAAM,CAAA,CAAE,SAAS,CAAA,EAAG;AAC5C,UAAA,MAAM,QAAA,GAAW,IAAA,CAAK,eAAA,CAAgB,MAAM,CAAA;AAC5C,UAAA,MAAM,OAAA,GAAU,IAAA,CAAK,aAAA,CAAc,GAAA,CAAI,QAAQ,CAAA,IAAK,CAAA;AACpD,UAAA,IAAA,CAAK,aAAA,CAAc,GAAA,CAAI,QAAA,EAAU,OAAA,GAAU,KAAK,CAAA;AAAA,QAClD,CAAA,MAAO;AACL,UAAA,IAAA,CAAK,KAAA,IAAS,KAAA;AAAA,QAChB;AAAA,MACF;AAAA;AAAA;AAAA;AAAA,MAKA,QAAA,GAAmB;AACjB,QAAA,OAAO,IAAA,CAAK,KAAA;AAAA,MACd;AAAA;AAAA;AAAA;AAAA;AAAA,MAMA,gBAAA,GAAwC;AACtC,QAAA,OAAO,IAAI,GAAA,CAAI,IAAA,CAAK,aAAa,CAAA;AAAA,MACnC;AAAA;AAAA;AAAA;AAAA,MAKA,kBAAkB,MAAA,EAAwC;AACxD,QAAA,MAAM,QAAA,GAAW,IAAA,CAAK,eAAA,CAAgB,MAAM,CAAA;AAC5C,QAAA,OAAO,IAAA,CAAK,aAAA,CAAc,GAAA,CAAI,QAAQ,CAAA,IAAK,CAAA;AAAA,MAC7C;AAAA;AAAA;AAAA;AAAA,MAKA,KAAA,GAAc;AACZ,QAAA,IAAA,CAAK,KAAA,GAAQ,CAAA;AACb,QAAA,IAAA,CAAK,cAAc,KAAA,EAAM;AAAA,MAC3B;AAAA;AAAA;AAAA;AAAA;AAAA,MAMQ,gBAAgB,MAAA,EAAwC;AAC9D,QAAA,OAAO,MAAA,CAAO,OAAA,CAAQ,MAAM,CAAA,CACzB,IAAA,CAAK,CAAC,CAAC,CAAC,CAAA,EAAG,CAAC,CAAC,CAAA,KAAM,EAAE,aAAA,CAAc,CAAC,CAAC,CAAA,CACrC,GAAA,CAAI,CAAC,CAAC,CAAA,EAAG,CAAC,CAAA,KAAM,CAAA,EAAG,CAAC,CAAA,CAAA,EAAI,CAAC,CAAA,CAAE,CAAA,CAC3B,KAAK,GAAG,CAAA;AAAA,MACb;AAAA,KACF;AAAA,EAAA;AAAA,CAAA,CAAA;ACwEA,eAAsB,eAAe,IAAA,EAAmD;AACtF,EAAA,OAAO,cAAA,CAAe,WAAA,EAAY,CAAE,cAAA,CAAe,IAAI,CAAA;AACzD;AA9LA,IAsCa,kBAAA,EAKP,cAAA;AA3CN,IAAA,aAAA,GAAA,KAAA,CAAA;AAAA,EAAA,2BAAA,GAAA;AAsCO,IAAM,kBAAA,GAAqB,CAAC,CAAA,EAAG,CAAA,EAAG,EAAA,EAAI,IAAI,GAAA,EAAK,GAAA,EAAK,GAAA,EAAM,GAAA,EAAM,GAAK,CAAA;AAK5E,IAAM,cAAA,GAAN,MAAM,eAAA,CAAe;AAAA,MACnB,OAAe,QAAA;AAAA,MACP,QAAA,GAAmC,IAAA;AAAA,MACnC,WAAA,GAA+C,IAAA;AAAA,MAC/C,SAAA,GAA0B,IAAA;AAAA,MAE1B,WAAA,GAAc;AAAA,MAEtB;AAAA;AAAA;AAAA;AAAA,MAKA,OAAO,WAAA,GAA8B;AACnC,QAAA,IAAI,CAAC,gBAAe,QAAA,EAAU;AAC5B,UAAA,eAAA,CAAe,QAAA,GAAW,IAAI,eAAA,EAAe;AAAA,QAC/C;AACA,QAAA,OAAO,eAAA,CAAe,QAAA;AAAA,MACxB;AAAA;AAAA;AAAA;AAAA,MAKA,MAAc,IAAA,GAAiC;AAC7C,QAAA,IAAI,IAAA,CAAK,aAAa,IAAA,EAAM;AAC1B,UAAA,OAAO,IAAA,CAAK,QAAA;AAAA,QACd;AAEA,QAAA,IAAI,IAAA,CAAK,cAAc,IAAA,EAAM;AAC3B,UAAA,MAAM,IAAA,CAAK,SAAA;AAAA,QACb;AAEA,QAAA,IAAI,KAAK,WAAA,EAAa;AACpB,UAAA,OAAO,IAAA,CAAK,WAAA;AAAA,QACd;AAEA,QAAA,IAAA,CAAK,eAAe,YAAY;AAC9B,UAAA,IAAI;AAGF,YAAA,MAAM,YAAA,GAAeA,IAAAA;AAAA,cACnB,SAAA;AAAA,cACA,IAAA;AAAA,cACA,IAAA;AAAA,cACA,QAAA;AAAA,cACA,aAAA;AAAA,cACA,UAAA;AAAA,cACA;AAAA,aACF;AAEA,YAAA,MAAM,OAAA,GAAU,MAAMC,QAAAA,CAAS,YAAA,EAAc,OAAO,CAAA;AACpD,YAAA,IAAA,CAAK,QAAA,GAAWC,MAAU,OAAO,CAAA;AAEjC,YAAA,OAAO,IAAA,CAAK,QAAA;AAAA,UACd,SAAS,GAAA,EAAK;AACZ,YAAA,IAAA,CAAK,SAAA,GAAY,eAAe,KAAA,GAAQ,GAAA,GAAM,IAAI,KAAA,CAAM,MAAA,CAAO,GAAG,CAAC,CAAA;AACnE,YAAA,MAAM,IAAI,KAAA,CAAM,CAAA,iCAAA,EAAoC,IAAA,CAAK,SAAA,CAAU,OAAO,CAAA,CAAE,CAAA;AAAA,UAC9E;AAAA,QACF,CAAA,GAAG;AAEH,QAAA,OAAO,IAAA,CAAK,WAAA;AAAA,MACd;AAAA;AAAA;AAAA;AAAA,MAKA,MAAM,WAAA,GAAwC;AAC5C,QAAA,OAAO,KAAK,IAAA,EAAK;AAAA,MACnB;AAAA;AAAA;AAAA;AAAA,MAKA,MAAM,UAAU,IAAA,EAAyD;AACvE,QAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,IAAA,EAAK;AACjC,QAAA,OAAO,SAAS,OAAA,CAAQ,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,SAAS,IAAI,CAAA;AAAA,MACrD;AAAA;AAAA;AAAA;AAAA,MAKA,MAAM,eAAe,IAAA,EAAmD;AACtE,QAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,SAAA,CAAU,IAAI,CAAA;AACxC,QAAA,OAAO,MAAA,EAAQ,IAAA;AAAA,MACjB;AAAA;AAAA;AAAA;AAAA;AAAA,MAMA,MAAM,kBAAkB,IAAA,EAAiD;AAEvE,QAAA,IAAI,IAAA,CAAK,QAAA,CAAS,KAAK,CAAA,EAAG;AACxB,UAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,IAAA,EAAK;AACjC,UAAA,OAAO,QAAA,CAAS,SAAS,iBAAA,CAAkB,UAAA;AAAA,QAC7C;AACA,QAAA,OAAO,MAAA;AAAA,MACT;AAAA;AAAA;AAAA;AAAA,MAKA,MAAM,kBAAkB,IAAA,EAAgC;AACtD,QAAA,IAAI;AACF,UAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,IAAA,EAAK;AACjC,UAAA,OAAO,SAAS,OAAA,CAAQ,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,SAAS,IAAI,CAAA;AAAA,QACrD,CAAA,CAAA,MAAQ;AACN,UAAA,OAAO,KAAA;AAAA,QACT;AAAA,MACF;AAAA;AAAA;AAAA;AAAA;AAAA,MAMA,OAAO,MAAA,GAAe;AACpB,QAAA,eAAA,CAAe,QAAA,GAAW,IAAI,eAAA,EAAe;AAAA,MAC/C;AAAA,KACF;AAAA,EAAA;AAAA,CAAA,CAAA;;;ACjKA,IA0Ba,SAAA;AA1Bb,IAAA,cAAA,GAAA,KAAA,CAAA;AAAA,EAAA,4BAAA,GAAA;AAOA,IAAA,aAAA,EAAA;AAmBO,IAAM,YAAN,MAAgB;AAAA,MAOrB,WAAA,CACkB,MAChB,OAAA,EACA;AAFgB,QAAA,IAAA,CAAA,IAAA,GAAA,IAAA;AAIhB,QAAA,IAAI,SAAS,OAAA,EAAS;AACpB,UAAA,IAAA,CAAK,OAAA,GAAU,CAAC,GAAG,OAAA,CAAQ,OAAO,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,CAAA,GAAI,CAAC,CAAA;AAAA,QAC1D,CAAA,MAAA,IAAW,KAAK,QAAA,CAAS,KAAK,KAAK,IAAA,CAAK,QAAA,CAAS,UAAU,CAAA,EAAG;AAC5D,UAAA,IAAA,CAAK,OAAA,GAAU,CAAC,GAAG,kBAAkB,CAAA;AAAA,QACvC,CAAA,MAAO;AACL,UAAA,IAAA,CAAK,UAAU,EAAC;AAAA,QAClB;AAGA,QAAA,KAAA,MAAW,MAAA,IAAU,KAAK,OAAA,EAAS;AACjC,UAAA,IAAA,CAAK,YAAA,CAAa,GAAA,CAAI,MAAA,EAAQ,CAAC,CAAA;AAAA,QACjC;AAAA,MACF;AAAA,MAvBQ,KAAA,GAAQ,CAAA;AAAA,MACR,GAAA,GAAM,CAAA;AAAA,MACN,YAAA,uBAAwC,GAAA,EAAI;AAAA,MAC5C,aAAA,uBAAoB,GAAA,EAAmC;AAAA,MAC9C,OAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAmCjB,OAAA,CAAQ,OAAe,MAAA,EAAuC;AAC5D,QAAA,IAAI,UAAU,MAAA,CAAO,IAAA,CAAK,MAAM,CAAA,CAAE,SAAS,CAAA,EAAG;AAE5C,UAAA,MAAM,QAAA,GAAW,IAAA,CAAK,eAAA,CAAgB,MAAM,CAAA;AAC5C,UAAA,IAAI,KAAA,GAAQ,IAAA,CAAK,aAAA,CAAc,GAAA,CAAI,QAAQ,CAAA;AAE3C,UAAA,IAAI,CAAC,KAAA,EAAO;AAEV,YAAA,KAAA,GAAQ;AAAA,cACN,KAAA,EAAO,CAAA;AAAA,cACP,GAAA,EAAK,CAAA;AAAA,cACL,YAAA,sBAAkB,GAAA;AAAI,aACxB;AACA,YAAA,KAAA,MAAW,MAAA,IAAU,KAAK,OAAA,EAAS;AACjC,cAAA,KAAA,CAAM,YAAA,CAAa,GAAA,CAAI,MAAA,EAAQ,CAAC,CAAA;AAAA,YAClC;AACA,YAAA,IAAA,CAAK,aAAA,CAAc,GAAA,CAAI,QAAA,EAAU,KAAK,CAAA;AAAA,UACxC;AAEA,UAAA,KAAA,CAAM,KAAA,EAAA;AACN,UAAA,KAAA,CAAM,GAAA,IAAO,KAAA;AAGb,UAAA,KAAA,MAAW,MAAA,IAAU,KAAK,OAAA,EAAS;AACjC,YAAA,IAAI,SAAS,MAAA,EAAQ;AACnB,cAAA,KAAA,CAAM,YAAA,CAAa,IAAI,MAAA,EAAA,CAAS,KAAA,CAAM,aAAa,GAAA,CAAI,MAAM,CAAA,IAAK,CAAA,IAAK,CAAC,CAAA;AAAA,YAC1E;AAAA,UACF;AAAA,QACF,CAAA,MAAO;AAEL,UAAA,IAAA,CAAK,KAAA,EAAA;AACL,UAAA,IAAA,CAAK,GAAA,IAAO,KAAA;AAGZ,UAAA,KAAA,MAAW,MAAA,IAAU,KAAK,OAAA,EAAS;AACjC,YAAA,IAAI,SAAS,MAAA,EAAQ;AACnB,cAAA,IAAA,CAAK,YAAA,CAAa,IAAI,MAAA,EAAA,CAAS,IAAA,CAAK,aAAa,GAAA,CAAI,MAAM,CAAA,IAAK,CAAA,IAAK,CAAC,CAAA;AAAA,YACxE;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAOA,UAAA,GAA+B;AAC7B,QAAA,MAAM,OAAA,GAA6B,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,CAAC,EAAA,MAAQ;AAAA,UAC3D,EAAA;AAAA,UACA,KAAA,EAAO,IAAA,CAAK,YAAA,CAAa,GAAA,CAAI,EAAE,CAAA,IAAK;AAAA,SACtC,CAAE,CAAA;AAEF,QAAA,OAAO;AAAA,UACL,OAAO,IAAA,CAAK,KAAA;AAAA,UACZ,KAAK,IAAA,CAAK,GAAA;AAAA,UACV;AAAA,SACF;AAAA,MACF;AAAA;AAAA;AAAA;AAAA,MAKA,QAAA,GAAmB;AACjB,QAAA,OAAO,IAAA,CAAK,KAAA;AAAA,MACd;AAAA;AAAA;AAAA;AAAA,MAKA,MAAA,GAAiB;AACf,QAAA,OAAO,IAAA,CAAK,GAAA;AAAA,MACd;AAAA;AAAA;AAAA;AAAA,MAKA,UAAA,GAAqB;AACnB,QAAA,OAAO,KAAK,KAAA,GAAQ,CAAA,GAAI,IAAA,CAAK,GAAA,GAAM,KAAK,KAAA,GAAQ,CAAA;AAAA,MAClD;AAAA;AAAA;AAAA;AAAA;AAAA,MAMA,mBAAA,GAAqD;AACnD,QAAA,MAAM,SAAA,uBAAgB,GAAA,EAA8B;AAEpD,QAAA,KAAA,MAAW,CAAC,QAAA,EAAU,KAAK,CAAA,IAAK,KAAK,aAAA,EAAe;AAClD,UAAA,MAAM,OAAA,GAA6B,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,CAAC,EAAA,MAAQ;AAAA,YAC3D,EAAA;AAAA,YACA,KAAA,EAAO,KAAA,CAAM,YAAA,CAAa,GAAA,CAAI,EAAE,CAAA,IAAK;AAAA,WACvC,CAAE,CAAA;AAEF,UAAA,SAAA,CAAU,IAAI,QAAA,EAAU;AAAA,YACtB,OAAO,KAAA,CAAM,KAAA;AAAA,YACb,KAAK,KAAA,CAAM,GAAA;AAAA,YACX;AAAA,WACD,CAAA;AAAA,QACH;AAEA,QAAA,OAAO,SAAA;AAAA,MACT;AAAA;AAAA;AAAA;AAAA,MAKA,oBAAoB,MAAA,EAAyD;AAC3E,QAAA,MAAM,QAAA,GAAW,IAAA,CAAK,eAAA,CAAgB,MAAM,CAAA;AAC5C,QAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,aAAA,CAAc,GAAA,CAAI,QAAQ,CAAA;AAE7C,QAAA,IAAI,CAAC,KAAA,EAAO;AACV,UAAA,OAAO,IAAA;AAAA,QACT;AAEA,QAAA,MAAM,OAAA,GAA6B,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,CAAC,EAAA,MAAQ;AAAA,UAC3D,EAAA;AAAA,UACA,KAAA,EAAO,KAAA,CAAM,YAAA,CAAa,GAAA,CAAI,EAAE,CAAA,IAAK;AAAA,SACvC,CAAE,CAAA;AAEF,QAAA,OAAO;AAAA,UACL,OAAO,KAAA,CAAM,KAAA;AAAA,UACb,KAAK,KAAA,CAAM,GAAA;AAAA,UACX;AAAA,SACF;AAAA,MACF;AAAA;AAAA;AAAA;AAAA,MAKA,KAAA,GAAc;AACZ,QAAA,IAAA,CAAK,KAAA,GAAQ,CAAA;AACb,QAAA,IAAA,CAAK,GAAA,GAAM,CAAA;AACX,QAAA,KAAA,MAAW,MAAA,IAAU,KAAK,OAAA,EAAS;AACjC,UAAA,IAAA,CAAK,YAAA,CAAa,GAAA,CAAI,MAAA,EAAQ,CAAC,CAAA;AAAA,QACjC;AACA,QAAA,IAAA,CAAK,cAAc,KAAA,EAAM;AAAA,MAC3B;AAAA;AAAA;AAAA;AAAA;AAAA,MAMQ,gBAAgB,MAAA,EAAwC;AAC9D,QAAA,OAAO,MAAA,CAAO,OAAA,CAAQ,MAAM,CAAA,CACzB,IAAA,CAAK,CAAC,CAAC,CAAC,CAAA,EAAG,CAAC,CAAC,CAAA,KAAM,EAAE,aAAA,CAAc,CAAC,CAAC,CAAA,CACrC,GAAA,CAAI,CAAC,CAAC,CAAA,EAAG,CAAC,CAAA,KAAM,CAAA,EAAG,CAAC,CAAA,CAAA,EAAI,CAAC,CAAA,CAAE,CAAA,CAC3B,KAAK,GAAG,CAAA;AAAA,MACb;AAAA,KACF;AAAA,EAAA;AAAA,CAAA,CAAA;;;ACvNA,IAmBa,eAAA;AAnBb,IAAAC,cAAAA,GAAA,KAAA,CAAA;AAAA,EAAA,2BAAA,GAAA;AAOA,IAAA,YAAA,EAAA;AACA,IAAA,UAAA,EAAA;AACA,IAAA,cAAA,EAAA;AACA,IAAA,aAAA,EAAA;AASO,IAAM,kBAAN,MAAsB;AAAA,MACnB,QAAA,uBAAyC,GAAA,EAAI;AAAA,MAC7C,MAAA,uBAAqC,GAAA,EAAI;AAAA,MACzC,UAAA,uBAA6C,GAAA,EAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAczD,QAAQ,IAAA,EAA2B;AACjC,QAAA,IAAI,OAAA,GAAU,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,IAAI,CAAA;AACpC,QAAA,IAAI,CAAC,OAAA,EAAS;AACZ,UAAA,OAAA,GAAU,IAAI,QAAQ,IAAI,CAAA;AAC1B,UAAA,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,IAAA,EAAM,OAAO,CAAA;AAAA,QACjC;AACA,QAAA,OAAO,OAAA;AAAA,MACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAcA,MAAM,IAAA,EAAyB;AAC7B,QAAA,IAAI,KAAA,GAAQ,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,IAAI,CAAA;AAChC,QAAA,IAAI,CAAC,KAAA,EAAO;AACV,UAAA,KAAA,GAAQ,IAAI,MAAM,IAAI,CAAA;AACtB,UAAA,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,IAAA,EAAM,KAAK,CAAA;AAAA,QAC7B;AACA,QAAA,OAAO,KAAA;AAAA,MACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAqBA,SAAA,CAAU,MAAkB,OAAA,EAAuC;AACjE,QAAA,IAAI,SAAA,GAAY,IAAA,CAAK,UAAA,CAAW,GAAA,CAAI,IAAI,CAAA;AACxC,QAAA,IAAI,CAAC,SAAA,EAAW;AACd,UAAA,SAAA,GAAY,IAAI,SAAA,CAAU,IAAA,EAAM,OAAO,CAAA;AACvC,UAAA,IAAA,CAAK,UAAA,CAAW,GAAA,CAAI,IAAA,EAAM,SAAS,CAAA;AAAA,QACrC;AACA,QAAA,OAAO,SAAA;AAAA,MACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAgBA,MAAM,MAAA,GAAkC;AACtC,QAAA,MAAM,SAAyB,EAAC;AAChC,QAAA,MAAM,SAAA,GAAA,iBAAY,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAGzC,QAAA,KAAA,MAAW,CAAC,IAAA,EAAM,OAAO,CAAA,IAAK,KAAK,QAAA,EAAU;AAC3C,UAAA,MAAM,IAAA,GAAO,MAAM,cAAA,CAAe,IAAI,CAAA;AAGtC,UAAA,MAAA,CAAO,IAAA,CAAK;AAAA,YACV,SAAA;AAAA,YACA,IAAA;AAAA,YACA,KAAA,EAAO,QAAQ,QAAA,EAAS;AAAA,YACxB;AAAA,WACD,CAAA;AAGD,UAAA,KAAA,MAAW,CAAC,QAAA,EAAU,KAAK,CAAA,IAAK,OAAA,CAAQ,kBAAiB,EAAG;AAC1D,YAAA,IAAI,QAAQ,CAAA,EAAG;AACb,cAAA,MAAM,IAAA,GAAO,IAAA,CAAK,iBAAA,CAAkB,QAAQ,CAAA;AAC5C,cAAA,MAAA,CAAO,IAAA,CAAK;AAAA,gBACV,SAAA;AAAA,gBACA,IAAA;AAAA,gBACA,KAAA;AAAA,gBACA,IAAA;AAAA,gBACA;AAAA,eACD,CAAA;AAAA,YACH;AAAA,UACF;AAAA,QACF;AAGA,QAAA,KAAA,MAAW,CAAC,IAAA,EAAM,KAAK,CAAA,IAAK,KAAK,MAAA,EAAQ;AACvC,UAAA,MAAM,IAAA,GAAO,MAAM,cAAA,CAAe,IAAI,CAAA;AAGtC,UAAA,MAAA,CAAO,IAAA,CAAK;AAAA,YACV,SAAA;AAAA,YACA,IAAA;AAAA,YACA,KAAA,EAAO,MAAM,QAAA,EAAS;AAAA,YACtB;AAAA,WACD,CAAA;AAGD,UAAA,KAAA,MAAW,CAAC,QAAA,EAAU,KAAK,CAAA,IAAK,KAAA,CAAM,kBAAiB,EAAG;AACxD,YAAA,MAAM,IAAA,GAAO,IAAA,CAAK,iBAAA,CAAkB,QAAQ,CAAA;AAC5C,YAAA,MAAA,CAAO,IAAA,CAAK;AAAA,cACV,SAAA;AAAA,cACA,IAAA;AAAA,cACA,KAAA;AAAA,cACA,IAAA;AAAA,cACA;AAAA,aACD,CAAA;AAAA,UACH;AAAA,QACF;AAGA,QAAA,KAAA,MAAW,CAAC,IAAA,EAAM,SAAS,CAAA,IAAK,KAAK,UAAA,EAAY;AAC/C,UAAA,MAAM,IAAA,GAAO,MAAM,cAAA,CAAe,IAAI,CAAA;AAGtC,UAAA,MAAA,CAAO,IAAA,CAAK;AAAA,YACV,SAAA;AAAA,YACA,IAAA;AAAA,YACA,KAAA,EAAO,UAAU,UAAA,EAAW;AAAA,YAC5B;AAAA,WACD,CAAA;AAGD,UAAA,KAAA,MAAW,CAAC,QAAA,EAAU,OAAO,CAAA,IAAK,SAAA,CAAU,qBAAoB,EAAG;AACjE,YAAA,IAAI,OAAA,CAAQ,QAAQ,CAAA,EAAG;AACrB,cAAA,MAAM,IAAA,GAAO,IAAA,CAAK,iBAAA,CAAkB,QAAQ,CAAA;AAC5C,cAAA,MAAA,CAAO,IAAA,CAAK;AAAA,gBACV,SAAA;AAAA,gBACA,IAAA;AAAA,gBACA,KAAA,EAAO,OAAA;AAAA,gBACP,IAAA;AAAA,gBACA;AAAA,eACD,CAAA;AAAA,YACH;AAAA,UACF;AAAA,QACF;AAEA,QAAA,OAAO,MAAA;AAAA,MACT;AAAA;AAAA;AAAA;AAAA;AAAA,MAMQ,kBAAkB,QAAA,EAA0C;AAClE,QAAA,IAAI,CAAC,QAAA,EAAU;AACb,UAAA,OAAO,EAAC;AAAA,QACV;AAEA,QAAA,MAAM,OAA+B,EAAC;AACtC,QAAA,KAAA,MAAW,IAAA,IAAQ,QAAA,CAAS,KAAA,CAAM,GAAG,CAAA,EAAG;AACtC,UAAA,MAAM,CAAC,GAAA,EAAK,KAAK,CAAA,GAAI,IAAA,CAAK,MAAM,GAAG,CAAA;AACnC,UAAA,IAAI,OAAO,KAAA,EAAO;AAChB,YAAA,IAAA,CAAK,GAAG,CAAA,GAAI,KAAA;AAAA,UACd;AAAA,QACF;AACA,QAAA,OAAO,IAAA;AAAA,MACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAsBA,MAAM,MAAM,OAAA,EAAiD;AAC3D,QAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,MAAA,EAAO;AAEjC,QAAA,IAAI;AAEF,UAAA,IAAI,SAAS,IAAA,EAAM;AACjB,YAAA,OAAA,CAAQ,KAAK,MAAM,CAAA;AAAA,UACrB;AAAA,QACF,CAAA,SAAE;AAEA,UAAA,IAAA,CAAK,KAAA,EAAM;AAAA,QACb;AAEA,QAAA,OAAO,MAAA;AAAA,MACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAOA,KAAA,GAAc;AACZ,QAAA,KAAA,MAAW,OAAA,IAAW,IAAA,CAAK,QAAA,CAAS,MAAA,EAAO,EAAG;AAC5C,UAAA,OAAA,CAAQ,KAAA,EAAM;AAAA,QAChB;AACA,QAAA,KAAA,MAAW,KAAA,IAAS,IAAA,CAAK,MAAA,CAAO,MAAA,EAAO,EAAG;AACxC,UAAA,KAAA,CAAM,KAAA,EAAM;AAAA,QACd;AACA,QAAA,KAAA,MAAW,SAAA,IAAa,IAAA,CAAK,UAAA,CAAW,MAAA,EAAO,EAAG;AAChD,UAAA,SAAA,CAAU,KAAA,EAAM;AAAA,QAClB;AAAA,MACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAQA,cAAA,GAA+B;AAC7B,QAAA,MAAM,KAAA,uBAAY,GAAA,EAAgB;AAClC,QAAA,KAAA,MAAW,IAAA,IAAQ,IAAA,CAAK,QAAA,CAAS,IAAA,EAAK,EAAG;AACvC,UAAA,KAAA,CAAM,IAAI,IAAI,CAAA;AAAA,QAChB;AACA,QAAA,KAAA,MAAW,IAAA,IAAQ,IAAA,CAAK,MAAA,CAAO,IAAA,EAAK,EAAG;AACrC,UAAA,KAAA,CAAM,IAAI,IAAI,CAAA;AAAA,QAChB;AACA,QAAA,KAAA,MAAW,IAAA,IAAQ,IAAA,CAAK,UAAA,CAAW,IAAA,EAAK,EAAG;AACzC,UAAA,KAAA,CAAM,IAAI,IAAI,CAAA;AAAA,QAChB;AACA,QAAA,OAAO,KAAA,CAAM,KAAK,KAAK,CAAA;AAAA,MACzB;AAAA;AAAA;AAAA;AAAA,MAKA,cAAA,GAAyB;AACvB,QAAA,OAAO,KAAK,QAAA,CAAS,IAAA,GAAO,KAAK,MAAA,CAAO,IAAA,GAAO,KAAK,UAAA,CAAW,IAAA;AAAA,MACjE;AAAA,KACF;AAAA,EAAA;AAAA,CAAA,CAAA;;;ACpSA,IAAA,UAAA,GAAA,KAAA,CAAA;AAAA,EAAA,wBAAA,GAAA;AAAA,EAAA;AAAA,CAAA,CAAA;;;ACAA,IAAA,eAAA,GAAA,KAAA,CAAA;AAAA,EAAA,6BAAA,GAAA;AAMA,IAAA,WAAA,EAAA;AAAA,EAAA;AAAA,CAAA,CAAA;;;ACNA,IAiCa,OAAA;AAjCb,IAAA,cAAA,GAAA,KAAA,CAAA;AAAA,EAAA,wBAAA,GAAA;AAUA,IAAAA,cAAAA,EAAAA;AAEA,IAAAA,cAAAA,EAAAA;AAwBA,IAAA,YAAA,EAAA;AACA,IAAA,UAAA,EAAA;AACA,IAAA,cAAA,EAAA;AAGA,IAAA,aAAA,EAAA;AAmBA,IAAA,UAAA,EAAA;AAOA,IAAA,eAAA,EAAA;AAlCO,IAAM,OAAA,GAAU,IAAI,eAAA,EAAgB;AAAA,EAAA;AAAA,CAAA,CAAA;ACe3C,eAAe,eAAe,KAAA,EAA4D;AACxF,EAAA,MAAM,UAAA,GAAaC,aAAAA,CAAc,MAAA,CAAA,IAAA,CAAY,GAAG,CAAA;AAChD,EAAA,MAAMC,UAAAA,GAAYC,QAAQ,UAAU,CAAA;AACpC,EAAA,MAAM,cAAA,GAAiBN,IAAAA;AAAA,IACrBK,UAAAA;AAAA,IACA,IAAA;AAAA,IACA,IAAA;AAAA,IACA,SAAA;AAAA,IACA,aAAA;AAAA,IACA,MAAA;AAAA,IACA,KAAA;AAAA,IACA;AAAA,GACF;AAEA,EAAA,MAAM,OAAA,GAAU,MAAMJ,QAAAA,CAAS,cAAA,EAAgB,OAAO,CAAA;AACtD,EAAA,OAAO,IAAA,CAAK,MAAM,OAAO,CAAA;AAC3B;AAKA,eAAe,sBAAsB,KAAA,EAA8D;AACjG,EAAA,IAAI,KAAA,KAAU,eAAA,IAAmB,KAAA,KAAU,eAAA,EAAiB;AAC1D,IAAA,OAAO,EAAC;AAAA,EACV;AAEA,EAAA,MAAM,UAAA,GAAaG,aAAAA,CAAc,MAAA,CAAA,IAAA,CAAY,GAAG,CAAA;AAChD,EAAA,MAAMC,UAAAA,GAAYC,QAAQ,UAAU,CAAA;AACpC,EAAA,MAAM,QAAA,GAAWN,KAAKK,UAAAA,EAAW,IAAA,EAAM,MAAM,SAAA,EAAW,aAAA,EAAe,MAAA,EAAQ,KAAA,EAAO,MAAM,CAAA;AAE5F,EAAA,MAAM,UAAA,GACJ,UAAU,eAAA,GACN;AAAA,IACE,WAAA;AAAA,IACA,iBAAA;AAAA,IACA,kBAAA;AAAA,IACA,iBAAA;AAAA,IACA,gBAAA;AAAA,IACA,wBAAA;AAAA,IACA;AAAA,GACF,GACA;AAAA,IACE,WAAA;AAAA,IACA,iBAAA;AAAA,IACA,iBAAA;AAAA,IACA,gBAAA;AAAA,IACA,aAAA;AAAA,IACA;AAAA,GACF;AAEN,EAAA,MAAM,UAAqC,EAAC;AAC5C,EAAA,KAAA,MAAW,QAAQ,UAAA,EAAY;AAC7B,IAAA,IAAI;AACF,MAAA,MAAM,UAAU,MAAMJ,QAAAA,CAASD,KAAK,QAAA,EAAU,IAAI,GAAG,OAAO,CAAA;AAC5D,MAAA,OAAA,CAAQ,IAAA,CAAK,IAAA,CAAK,KAAA,CAAM,OAAO,CAA4B,CAAA;AAAA,IAC7D,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF;AAEA,EAAA,OAAO,OAAA;AACT;AAcA,eAAe,qBAAqB,GAAA,EAA+C;AACjF,EAAA,MAAM,UAAA,GAAaI,aAAAA,CAAc,MAAA,CAAA,IAAA,CAAY,GAAG,CAAA;AAChD,EAAA,MAAMC,UAAAA,GAAYC,QAAQ,UAAU,CAAA;AACpC,EAAA,MAAM,QAAA,GAAWN,IAAAA,CAAKK,UAAAA,EAAW,IAAA,EAAM,IAAI,CAAA;AAE3C,EAAA,IAAI,YAAA;AAGJ,EAAA,IAAI,GAAA,CAAI,UAAA,CAAW,+BAA+B,CAAA,EAAG;AACnD,IAAA,IAAI,YAAA,GAAe,GAAA,CAAI,OAAA,CAAQ,+BAAA,EAAiC,EAAE,CAAA;AAIlE,IAAA,IAAI,YAAA,CAAa,UAAA,CAAW,WAAW,CAAA,EAAG;AACxC,MAAA,YAAA,GAAe,YAAA,CAAa,KAAA,CAAM,WAAA,CAAY,MAAM,CAAA;AAAA,IACtD;AAGA,IAAA,IAAI,YAAA,CAAa,UAAA,CAAW,kBAAkB,CAAA,EAAG;AAC/C,MAAA,YAAA,GAAeL,IAAAA;AAAA,QACb,QAAA;AAAA,QACA,QAAA;AAAA,QACA,aAAA;AAAA,QACA,UAAA;AAAA,QACA,YAAA,CAAa,KAAA,CAAM,GAAG,CAAA,CAAE,KAAI,IAAK;AAAA,OACnC;AAAA,IACF,CAAA,MAAO;AAEL,MAAA,YAAA,GAAeA,IAAAA,CAAK,QAAA,EAAU,SAAA,EAAW,aAAA,EAAe,YAAY,CAAA;AAAA,IACtE;AAAA,EACF,CAAA,MAAA,IAES,IAAI,UAAA,CAAW,QAAQ,KAAK,GAAA,CAAI,UAAA,CAAW,KAAK,CAAA,EAAG;AAG1D,IAAA,MAAM,UAAA,GAAaA,IAAAA;AAAA,MACjB,QAAA;AAAA,MACA,SAAA;AAAA,MACA,aAAA;AAAA,MACA,eAAA;AAAA,MACA,SAAA;AAAA,MACA;AAAA,KACF;AACA,IAAA,YAAA,GAAeA,IAAAA,CAAK,YAAY,GAAG,CAAA;AAAA,EACrC,CAAA,MAAA,IAES,GAAA,CAAI,UAAA,CAAW,SAAS,CAAA,EAAG;AAClC,IAAA,YAAA,GAAeI,cAAc,GAAG,CAAA;AAAA,EAClC,CAAA,MAEK;AACH,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,2BAAA,EAA8B,GAAG,CAAA,CAAE,CAAA;AAAA,EACrD;AAGA,EAAA,MAAM,OAAA,GAAU,MAAMH,QAAAA,CAAS,YAAA,EAAc,OAAO,CAAA;AACpD,EAAA,MAAM,MAAM,YAAA,CAAa,KAAA,CAAM,GAAG,CAAA,CAAE,GAAA,IAAO,WAAA,EAAY;AAEvD,EAAA,IAAI,GAAA,KAAQ,MAAA,IAAU,GAAA,KAAQ,KAAA,EAAO;AACnC,IAAA,OAAOM,MAAU,OAAO,CAAA;AAAA,EAC1B;AACA,EAAA,OAAO,IAAA,CAAK,MAAM,OAAO,CAAA;AAC3B;AAKA,SAAS,cAAc,MAAA,EAAoC;AACzD,EAAA,IAAI,MAAA,IAAU,OAAO,MAAA,KAAW,QAAA,IAAY,CAAC,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA,EAAG;AAClE,IAAA,MAAM,WAAA,GAAc,MAAA;AACpB,IAAA,MAAM,WAAY,WAAA,CAAsC,OAAA;AAExD,IAAA,IAAI,OAAO,aAAa,QAAA,EAAU;AAChC,MAAA,IAAI,QAAA,CAAS,QAAA,CAAS,UAAU,CAAA,EAAG,OAAO,UAAA;AAC1C,MAAA,IAAI,QAAA,CAAS,QAAA,CAAS,UAAU,CAAA,EAAG,OAAO,UAAA;AAC1C,MAAA,IAAI,QAAA,CAAS,QAAA,CAAS,UAAU,CAAA,EAAG,OAAO,UAAA;AAC1C,MAAA,IAAI,QAAA,CAAS,QAAA,CAAS,eAAe,CAAA,EAAG,OAAO,eAAA;AAC/C,MAAA,IAAI,QAAA,CAAS,QAAA,CAAS,eAAe,CAAA,EAAG,OAAO,eAAA;AAAA,IACjD;AAAA,EACF;AAGA,EAAA,OAAO,eAAA;AACT;AAKA,SAAS,UAAU,OAAA,EAAiC;AAClD,EAAA,MAAM,OAAA,GACJ,YAAY,eAAA,GACR,OAAA,GACA,YAAY,eAAA,GACV,OAAA,GACA,OAAA,KAAY,UAAA,GACT,UAAA,GACD,GAAA;AAEV,EAAA,MAAM,GAAA,GAAM,IAAI,OAAA,CAAQ;AAAA,IACtB,MAAA,EAAQ,KAAA;AAAA,IACR,SAAA,EAAW,IAAA;AAAA,IACX,OAAA,EAAS,IAAA;AAAA;AAAA,IAET,aAAA,EAAe,KAAA;AAAA;AAAA,IAEf,QAAA,EAAU,OAAA,KAAY,UAAA,GAAa,IAAA,GAAO,KAAA;AAAA;AAAA,IAE1C,UAAA,EAAY;AAAA,GACb,CAAA;AAED,EAAA,qBAAA,CAAsB,GAAG,CAAA;AAEzB,EAAA,OAAO,GAAA;AACT;AAKA,eAAe,OAAO,OAAA,EAA0C;AAC9D,EAAA,MAAM,QAAA,GAAW,YAAA,CAAa,GAAA,CAAI,OAAO,CAAA;AACzC,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,MAAM,KAAA,GAAQ,eAAA,CAAgB,GAAA,CAAI,OAAO,CAAA;AACzC,IAAA,IAAI,OAAO,MAAM,KAAA;AACjB,IAAA,OAAO,QAAA;AAAA,EACT;AAEA,EAAA,MAAM,GAAA,GAAM,UAAU,OAAO,CAAA;AAC7B,EAAA,YAAA,CAAa,GAAA,CAAI,SAAS,GAAG,CAAA;AAE7B,EAAA,MAAM,eAAe,OAAA,CAAQ,GAAA,CAAI,CAAC,qBAAA,CAAsB,OAAO,CAAA,EAAG,cAAA,CAAe,OAAO,CAAC,CAAC,CAAA,CACvF,IAAA,CAAK,CAAC,CAAC,YAAA,EAAc,UAAU,CAAA,KAAM;AAEpC,IAAA,KAAA,MAAW,eAAe,YAAA,EAAc;AACtC,MAAA,IAAI;AACF,QAAA,GAAA,CAAI,cAAc,WAAW,CAAA;AAAA,MAC/B,CAAA,CAAA,MAAQ;AAAA,MAER;AAAA,IACF;AAEA,IAAA,IAAI;AACF,MAAA,GAAA,CAAI,cAAc,UAAU,CAAA;AAAA,IAC9B,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF,CAAC,CAAA,CACA,KAAA,CAAM,CAAC,KAAA,KAAU;AAChB,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,4BAAA,EAA+B,OAAO,CAAA,GAAA,EAAM,KAAK,CAAA,CAAE,CAAA;AAAA,EACrE,CAAC,CAAA;AAEH,EAAA,eAAA,CAAgB,GAAA,CAAI,SAAS,YAAY,CAAA;AACzC,EAAA,MAAM,YAAA;AAEN,EAAA,OAAO,GAAA;AACT;AAKA,eAAsB,aAAA,CACpB,MAAA,EACA,OAAA,GAAkC,EAAC,EACP;AAC5B,EAAA,MAAM,UAAU,OAAO,MAAA,KAAW,WAAW,MAAA,GAAS,IAAA,CAAK,UAAU,MAAM,CAAA;AAE3E,EAAA,IAAI,YAAA;AACJ,EAAA,IAAI,OAAO,WAAW,QAAA,EAAU;AAC9B,IAAA,IAAI;AACF,MAAA,YAAA,GAAe,IAAA,CAAK,MAAM,MAAM,CAAA;AAAA,IAClC,CAAA,CAAA,MAAQ;AAEN,MAAA,YAAA,GAAeA,MAAU,MAAM,CAAA;AAAA,IACjC;AAAA,EACF,CAAA,MAAA,IAAW,MAAA,CAAO,QAAA,CAAS,MAAM,CAAA,EAAG;AAClC,IAAA,MAAM,OAAA,GAAU,MAAA,CAAO,QAAA,CAAS,OAAO,CAAA;AACvC,IAAA,IAAI;AACF,MAAA,YAAA,GAAe,IAAA,CAAK,MAAM,OAAO,CAAA;AAAA,IACnC,CAAA,CAAA,MAAQ;AACN,MAAA,YAAA,GAAeA,MAAU,OAAO,CAAA;AAAA,IAClC;AAAA,EACF,CAAA,MAAO;AACL,IAAA,YAAA,GAAe,MAAA;AAAA,EACjB;AAEA,EAAA,MAAM,OAAA,GAAU,cAAc,YAAY,CAAA;AAC1C,EAAA,MAAM,GAAA,GAAM,MAAM,MAAA,CAAO,OAAO,CAAA;AAEhC,EAAA,MAAM,QAAA,GAAW,CAAA,EAAG,OAAO,CAAA,CAAA,EAAI,OAAO,CAAA,CAAA;AACtC,EAAA,MAAM,MAAA,GAAS,WAAA,CAAY,GAAA,CAAI,QAAQ,CAAA;AACvC,EAAA,IAAI,WAAW,MAAA,EAAW;AACxB,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,IAAI;AAEF,IAAA,IAAI,OAAA,CAAQ,OAAA,IAAW,OAAA,CAAQ,OAAA,CAAQ,SAAS,CAAA,EAAG;AACjD,MAAA,KAAA,MAAW,KAAA,IAAS,QAAQ,OAAA,EAAS;AACnC,QAAA,IAAI,KAAA,IAAS,GAAA,CAAI,SAAA,CAAU,KAAK,MAAM,KAAA,CAAA,EAAW;AAC/C,UAAA,IAAI;AACF,YAAA,IAAI,OAAO,YAAA,KAAiB,QAAA,IAAY,YAAA,KAAiB,IAAA,EAAM;AAC7D,cAAA,GAAA,CAAI,SAAA,CAAU,cAAyC,KAAK,CAAA;AAAA,YAC9D;AAAA,UACF,CAAA,CAAA,MAAQ;AAAA,UAER;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,IAAA,MAAM,SAAA,GACJ,OAAO,YAAA,KAAiB,SAAA,GACpB,GAAA,CAAI,OAAA,CAAQ,YAAY,CAAA,GACxB,MAAM,GAAA,CAAI,YAAA,CAAa,YAAuC,CAAA;AAGpE,IAAA,WAAA,CAAY,GAAA,CAAI,UAAU,SAA8B,CAAA;AAExD,IAAA,OAAO,SAAA;AAAA,EACT,SAAS,KAAA,EAAO;AACd,IAAA,MAAM,qBAAA,CAAsB,WAAA;AAAA,MAC1B;AAAA,QACE,IAAA,EAAM,QAAA;AAAA,QACN,SAAS,OAAO,MAAA,KAAW,WAAW,MAAA,GAAS,IAAA,CAAK,UAAU,MAAM;AAAA,OACtE;AAAA,MACA;AAAA,KACF;AAAA,EACF;AACF;AAKO,SAAS,YAAA,CAAa,MAAe,SAAA,EAAsD;AAChG,EAAA,MAAM,KAAA,GAAQ,UAAU,IAAI,CAAA;AAE5B,EAAA,MAAM,MAAA,GAAiC;AAAA,IACrC,KAAA;AAAA,IACA,aAAa,EAAC;AAAA,IACd,MAAA,EAAQ;AAAA,GACV;AAEA,EAAA,IAAI,CAAC,KAAA,IAAS,SAAA,CAAU,MAAA,EAAQ;AAC9B,IAAA,MAAM,SAAS,SAAA,CAAU,MAAA;AACzB,IAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA,EAAG;AACzB,MAAA,MAAA,CAAO,cAAc,MAAA,CAAO,GAAA;AAAA,QAAI,CAAC,KAAA,KAC/B,gBAAA;AAAA,UACE,MAAM,YAAA,IAAgB,EAAA;AAAA,UACtB,MAAM,OAAA,IAAW,mBAAA;AAAA,UACjB,MAAM,OAAA,IAAW,SAAA;AAAA,UACjB,OAAA;AAAA,UACA;AAAA;AACF,OACF;AAAA,IACF;AACA,IAAA,OAAA,CAAQ,OAAA,CAAQ,0BAA0B,CAAA,CAAE,GAAA,EAAI;AAAA,EAClD,CAAA,MAAO;AACL,IAAA,OAAA,CAAQ,OAAA,CAAQ,oBAAoB,CAAA,CAAE,GAAA,EAAI;AAAA,EAC5C;AAEA,EAAA,OAAO,MAAA;AACT;AA/XA,IAiCM,cAKA,eAAA,EAKA,WAAA;AA3CN,IAAA,cAAA,GAAA,KAAA,CAAA;AAAA,EAAA,yBAAA,GAAA;AAaA,IAAA,cAAA,EAAA;AACA,IAAA,gBAAA,EAAA;AACA,IAAA,WAAA,EAAA;AACA,IAAA,aAAA,EAAA;AAOA,IAAA,UAAA,EAAA;AAUA,IAAM,YAAA,uBAAmB,GAAA,EAA4B;AAKrD,IAAM,eAAA,uBAAsB,GAAA,EAAsC;AAKlE,IAAM,WAAA,uBAAkB,GAAA,EAA+B;AAAA,EAAA;AAAA,CAAA,CAAA;AC3CvD,IAAA,QAAA,GAAA,KAAA,CAAA;AAAA,EAAA,mBAAA,GAAA;AAUA,IAAA,kBAAA,EAAA;AACA,IAAA,eAAA,EAAA;AACA,IAAA,aAAA,EAAA;AAEA,IAAA,UAAA,EAAA;AACA,IAAA,cAAA,EAAA;AAAA,EAAA;AAAA,CAAA,CAAA;ACfA,IAAA,WAAA,GAAA,KAAA,CAAA;AAAA,EAAA,sBAAA,GAAA;AAQA,IAAA,WAAA,EAAA;AACA,IAAA,aAAA,EAAA;AAOA,IAAA,cAAA,EAAA;AAAA,EAAA;AAAA,CAAA,CAAA;;;AChBA,IAAA,WAAA,GAAA,KAAA,CAAA;AAAA,EAAA,qBAAA,GAAA;AASA,IAAA,gBAAA,EAAA;AAMA,IAAA,QAAA,EAAA;AAEA,IAAA,WAAA,EAAA;AAEA,IAAA,WAAA,EAAA;AAEA,IAAA,kBAAA,EAAA;AAMA,IAAA,eAAA,EAAA;AAEA,IAAA,aAAA,EAAA;AA6BA,IAAA,UAAA,EAAA;AAUA,IAAA,cAAA,EAAA;AAAA,EAAA;AAAA,CAAA,CAAA;;;ACxCO,SAAS,iBAAA,CACd,KACA,gBAAA,EACyB;AACzB,EAAA,MAAM,GAAA,GAA0C,EAAE,GAAG,GAAA,EAAI;AACzD,EAAA,MAAM,UAA6D,EAAC;AACpE,EAAA,MAAM,YAAgC,EAAC;AAEvC,EAAA,KAAA,MAAW,CAAC,QAAA,EAAU,YAAY,KAAK,MAAA,CAAO,OAAA,CAAQ,gBAAgB,CAAA,EAAG;AACvE,IAAA,MAAM,UAAA,GAAa,IAAI,QAAQ,CAAA;AAC/B,IAAA,IAAI,UAAA,KAAe,MAAA,IAAa,UAAA,KAAe,EAAA,EAAI;AAEnD,IAAA,MAAM,cAAA,GAAiB,IAAI,YAAY,CAAA;AACvC,IAAA,IAAI,cAAA,KAAmB,MAAA,IAAa,cAAA,KAAmB,EAAA,EAAI;AACzD,MAAA,GAAA,CAAI,YAAY,CAAA,GAAI,UAAA;AACpB,MAAA,OAAA,CAAQ,IAAA,CAAK,EAAE,QAAA,EAAU,YAAA,EAAc,CAAA;AACvC,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,mBAAmB,UAAA,EAAY;AACjC,MAAA,SAAA,CAAU,IAAA,CAAK;AAAA,QACb,YAAA;AAAA,QACA,QAAA;AAAA,QACA,cAAA;AAAA,QACA;AAAA,OACD,CAAA;AAAA,IACH;AAAA,EACF;AAEA,EAAA,OAAO,EAAE,GAAA,EAAK,GAAA,EAAK,OAAA,EAAS,SAAA,EAAU;AACxC;;;ACnDO,IAAM,eAAA,GAAN,MAAM,gBAAA,SAAwB,KAAA,CAAM;AAAA,EACzC,WAAA,CACE,SACO,KAAA,EACP;AACA,IAAA,KAAA,CAAM,OAAO,CAAA;AAFN,IAAA,IAAA,CAAA,KAAA,GAAA,KAAA;AAGP,IAAA,IAAA,CAAK,IAAA,GAAO,iBAAA;AAGZ,IAAA,IAAI,MAAM,iBAAA,EAAmB;AAC3B,MAAA,KAAA,CAAM,iBAAA,CAAkB,MAAM,gBAAe,CAAA;AAAA,IAC/C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,qBAAqB,UAAA,EAAsC;AAChE,IAAA,OAAO,IAAI,gBAAA;AAAA,MACT,CAAA,gCAAA,EAAmC,IAAA,CAAK,SAAA,CAAU,UAAU,CAAC,CAAA,0CAAA;AAAA,KAC/D;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,WAAA,CAAY,IAAA,EAAc,IAAA,EAAyC;AACxE,IAAA,OAAO,IAAI,gBAAA;AAAA,MACT,CAAA,QAAA,EAAW,IAAI,CAAA,QAAA,EAAW,IAAI,CAAA,4DAAA;AAAA,KAChC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,eAAA,GAAmC;AACxC,IAAA,OAAO,IAAI,gBAAA;AAAA,MACT;AAAA,KACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,uBAAA,CAAwB,IAAA,EAAc,KAAA,EAA+B;AAC1E,IAAA,OAAO,IAAI,gBAAA,CAAgB,CAAA,4BAAA,EAA+B,IAAI,IAAI,KAAK,CAAA;AAAA,EACzE;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,aAAA,CAAc,OAAA,EAAiB,KAAA,EAAgC;AACpE,IAAA,OAAO,IAAI,gBAAA;AAAA,MACT,CAAA,6BAAA,EAAgC,OAAO,CAAA,EAAA,EAAK,KAAK,CAAA,uDAAA;AAAA,KACnD;AAAA,EACF;AACF;AAKO,IAAM,qBAAA,GAAN,MAAM,sBAAA,SAA8B,KAAA,CAAM;AAAA,EAC/C,WAAA,CACE,OAAA,EACO,WAAA,EACA,KAAA,EACP;AACA,IAAA,KAAA,CAAM,OAAO,CAAA;AAHN,IAAA,IAAA,CAAA,WAAA,GAAA,WAAA;AACA,IAAA,IAAA,CAAA,KAAA,GAAA,KAAA;AAGP,IAAA,IAAA,CAAK,IAAA,GAAO,uBAAA;AAEZ,IAAA,IAAI,MAAM,iBAAA,EAAmB;AAC3B,MAAA,KAAA,CAAM,iBAAA,CAAkB,MAAM,sBAAqB,CAAA;AAAA,IACrD;AAAA,EACF;AACF;;;AC9EA,WAAA,EAAA;;;ACOA,cAAA,EAAA;AAOA,SAAS,eAAA,GAAgC;AACvC,EAAA,MAAM,aAAa,OAAA,CAAQ,QAAA;AAC3B,EAAA,MAAM,UAAU,OAAA,EAAQ;AAExB,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,MAAM,gBAAgB,eAAA,EAAgB;AAAA,EACxC;AAEA,EAAA,MAAM,YAAA,GAA6B;AAAA,IACjC,QAAA,EACE,eAAe,OAAA,GACX,OAAA,GACA,eAAe,QAAA,GACb,QAAA,GACA,UAAA,KAAe,OAAA,GACb,OAAA,GACA,SAAA;AAAA,IACV;AAAA,GACF;AAGA,EAAA,IAAI,eAAe,OAAA,EAAS;AAC1B,IAAA,YAAA,CAAa,MAAA,GAAS;AAAA,MACpB,eAAA,EAAiB,QAAQ,GAAA,CAAI,eAAA;AAAA,MAC7B,aAAA,EAAe,QAAQ,GAAA,CAAI,aAAA;AAAA,MAC3B,cAAA,EAAgB,QAAQ,GAAA,CAAI;AAAA,KAC9B;AAAA,EACF;AAGA,EAAA,IAAI,eAAe,OAAA,EAAS;AAC1B,IAAA,YAAA,CAAa,MAAA,GAAS;AAAA,MACpB,OAAA,EAAS,QAAQ,GAAA,CAAI,OAAA;AAAA,MACrB,YAAA,EAAc,QAAQ,GAAA,CAAI;AAAA,KAC5B;AAAA,EACF;AAEA,EAAA,OAAO,YAAA;AACT;AAKA,SAAS,iBAAA,CAAkB,MAAc,IAAA,EAA8B;AACrE,EAAA,IAAI,CAAC,IAAA,IAAQ,OAAO,IAAA,KAAS,QAAA,EAAU;AACrC,IAAA,MAAM,eAAA,CAAgB,WAAA,CAAY,IAAA,EAAM,IAAI,CAAA;AAAA,EAC9C;AAGA,EAAA,IAAI,CAAC,0BAAA,CAA2B,IAAA,CAAK,IAAI,CAAA,EAAG;AAC1C,IAAA,MAAM,eAAA,CAAgB,WAAA,CAAY,IAAA,EAAM,IAAI,CAAA;AAAA,EAC9C;AACF;AAKA,SAAS,sBAAsB,GAAA,EAA0B;AACvD,EAAA,IAAI,CAAC,GAAA,IAAO,OAAO,GAAA,KAAQ,QAAA,EAAU;AACnC,IAAA,MAAM,eAAA,CAAgB,qBAAqB,GAAG,CAAA;AAAA,EAChD;AAEA,EAAA,IAAI,CAAC,GAAA,CAAI,MAAA,IAAU,CAAC,IAAI,GAAA,EAAK;AAC3B,IAAA,MAAM,eAAA,CAAgB,qBAAqB,GAAG,CAAA;AAAA,EAChD;AAEA,EAAA,iBAAA,CAAkB,GAAA,CAAI,QAAQ,QAAQ,CAAA;AACtC,EAAA,iBAAA,CAAkB,GAAA,CAAI,KAAK,KAAK,CAAA;AAClC;AAKA,SAAS,kBAAA,CAAmB,IAAA,EAAc,OAAA,EAAiB,OAAA,EAAuB;AAChF,EAAA,IAAI,CAAC,UAAA,CAAW,IAAI,CAAA,EAAG;AACrB,IAAA,MAAM,eAAA,CAAgB,aAAA,CAAc,OAAA,EAAS,IAAI,CAAA;AAAA,EACnD;AAIA,EAAA,MAAM,YAAA,GAAe,QAAQ,IAAI,CAAA;AACjC,EAAA,MAAM,YAAA,GAAe,QAAQ,OAAO,CAAA;AAGpC,EAAA,MAAM,SAAA,GAAY,QAAQ,QAAA,KAAa,OAAA;AACvC,EAAA,MAAM,cAAA,GAAiB,SAAA,GAAY,YAAA,CAAa,WAAA,EAAY,GAAI,YAAA;AAChE,EAAA,MAAM,cAAA,GAAiB,SAAA,GAAY,YAAA,CAAa,WAAA,EAAY,GAAI,YAAA;AAEhE,EAAA,IAAI,CAAC,cAAA,CAAe,UAAA,CAAW,cAAc,CAAA,EAAG;AAC9C,IAAA,MAAM,eAAA,CAAgB,aAAA,CAAc,OAAA,EAAS,IAAI,CAAA;AAAA,EACnD;AACF;AAKO,SAAS,cAAA,CAAe,OAAA,GAA6B,EAAC,EAAgB;AAC3E,EAAA,MAAM,eAAe,eAAA,EAAgB;AACrC,EAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,aAAA,IAAiB,YAAA,CAAa,OAAA;AAGtD,EAAA,MAAM,UAAA,GACJ,QAAQ,GAAA,CAAI,kBAAA,IAAsB,QAAQ,GAAA,CAAI,eAAA,IAAmBP,IAAAA,CAAK,OAAA,EAAS,SAAS,CAAA;AAE1F,EAAA,MAAM,QAAA,GACJ,OAAA,CAAQ,GAAA,CAAI,gBAAA,IAAoB,OAAA,CAAQ,IAAI,aAAA,IAAiBA,IAAAA,CAAK,OAAA,EAAS,QAAA,EAAU,OAAO,CAAA;AAE9F,EAAA,MAAM,SAAA,GACJ,QAAQ,GAAA,CAAI,iBAAA,IAAqB,QAAQ,GAAA,CAAI,cAAA,IAAkBA,IAAAA,CAAK,OAAA,EAAS,QAAQ,CAAA;AAGvF,EAAA,IAAI,OAAA,CAAQ,IAAI,kBAAA,EAAoB;AAClC,IAAA,kBAAA,CAAmB,UAAA,EAAY,sBAAsB,OAAO,CAAA;AAAA,EAC9D;AACA,EAAA,IAAI,OAAA,CAAQ,IAAI,gBAAA,EAAkB;AAChC,IAAA,kBAAA,CAAmB,QAAA,EAAU,oBAAoB,OAAO,CAAA;AAAA,EAC1D;AACA,EAAA,IAAI,OAAA,CAAQ,IAAI,iBAAA,EAAmB;AACjC,IAAA,kBAAA,CAAmB,SAAA,EAAW,qBAAqB,OAAO,CAAA;AAAA,EAC5D;AAEA,EAAA,OAAO;AAAA,IACL,UAAA;AAAA,IACA,QAAA;AAAA,IACA;AAAA,GACF;AACF;AAKA,SAAS,mBAAA,CAAoB,OAAA,GAA6B,EAAC,EAAgB;AACzE,EAAA,MAAM,eAAe,eAAA,EAAgB;AACrC,EAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,aAAA,IAAiB,YAAA,CAAa,OAAA;AAEtD,EAAA,QAAQ,aAAa,QAAA;AAAU,IAC7B,KAAK,QAAA,EAAU;AAEb,MAAA,MAAM,UAAA,GAAaA,IAAAA,CAAK,OAAA,EAAS,SAAA,EAAW,qBAAqB,CAAA;AACjE,MAAA,MAAM,YAAA,GAAeA,IAAAA,CAAK,OAAA,EAAS,SAAA,EAAW,QAAQ,CAAA;AAGtD,MAAA,IAAI,UAAA,GAAa,UAAA;AACjB,MAAA,IAAI,QAAA,GAAW,UAAA;AACf,MAAA,IAAI,SAAA,GAAY,YAAA;AAGhB,MAAA,IAAI,OAAA,CAAQ,IAAI,kBAAA,EAAoB;AAClC,QAAA,kBAAA,CAAmB,OAAA,CAAQ,GAAA,CAAI,kBAAA,EAAoB,oBAAA,EAAsB,OAAO,CAAA;AAChF,QAAA,UAAA,GAAa,QAAQ,GAAA,CAAI,kBAAA;AAAA,MAC3B;AACA,MAAA,IAAI,OAAA,CAAQ,IAAI,gBAAA,EAAkB;AAChC,QAAA,kBAAA,CAAmB,OAAA,CAAQ,GAAA,CAAI,gBAAA,EAAkB,kBAAA,EAAoB,OAAO,CAAA;AAC5E,QAAA,QAAA,GAAW,QAAQ,GAAA,CAAI,gBAAA;AAAA,MACzB;AACA,MAAA,IAAI,OAAA,CAAQ,IAAI,iBAAA,EAAmB;AACjC,QAAA,kBAAA,CAAmB,OAAA,CAAQ,GAAA,CAAI,iBAAA,EAAmB,mBAAA,EAAqB,OAAO,CAAA;AAC9E,QAAA,SAAA,GAAY,QAAQ,GAAA,CAAI,iBAAA;AAAA,MAC1B;AAEA,MAAA,OAAO,EAAE,UAAA,EAAY,QAAA,EAAU,SAAA,EAAU;AAAA,IAC3C;AAAA,IAEA,KAAK,OAAA,EAAS;AAEZ,MAAA,MAAM,UAAU,YAAA,CAAa,MAAA,EAAQ,WAAWA,IAAAA,CAAK,OAAA,EAAS,WAAW,SAAS,CAAA;AAClF,MAAA,MAAM,eAAe,YAAA,CAAa,MAAA,EAAQ,gBAAgBA,IAAAA,CAAK,OAAA,EAAS,WAAW,OAAO,CAAA;AAC1F,MAAA,MAAM,QAAA,GAAWA,IAAAA,CAAK,YAAA,EAAc,OAAO,CAAA;AAG3C,MAAA,IAAI,UAAA,GAAa,OAAA;AACjB,MAAA,IAAI,QAAA,GAAW,YAAA;AACf,MAAA,IAAI,SAAA,GAAY,QAAA;AAGhB,MAAA,IAAI,OAAA,CAAQ,IAAI,kBAAA,EAAoB;AAClC,QAAA,kBAAA,CAAmB,OAAA,CAAQ,GAAA,CAAI,kBAAA,EAAoB,oBAAA,EAAsB,OAAO,CAAA;AAChF,QAAA,UAAA,GAAa,QAAQ,GAAA,CAAI,kBAAA;AAAA,MAC3B;AACA,MAAA,IAAI,OAAA,CAAQ,IAAI,gBAAA,EAAkB;AAChC,QAAA,kBAAA,CAAmB,OAAA,CAAQ,GAAA,CAAI,gBAAA,EAAkB,kBAAA,EAAoB,OAAO,CAAA;AAC5E,QAAA,QAAA,GAAW,QAAQ,GAAA,CAAI,gBAAA;AAAA,MACzB;AACA,MAAA,IAAI,OAAA,CAAQ,IAAI,iBAAA,EAAmB;AACjC,QAAA,kBAAA,CAAmB,OAAA,CAAQ,GAAA,CAAI,iBAAA,EAAmB,mBAAA,EAAqB,OAAO,CAAA;AAC9E,QAAA,SAAA,GAAY,QAAQ,GAAA,CAAI,iBAAA;AAAA,MAC1B;AAEA,MAAA,OAAO,EAAE,UAAA,EAAY,QAAA,EAAU,SAAA,EAAU;AAAA,IAC3C;AAAA,IAEA,KAAK,OAAA;AAEH,MAAA,OAAO,eAAe,OAAO,CAAA;AAAA,IAE/B;AAEE,MAAA,OAAO,eAAe,OAAO,CAAA;AAAA;AAEnC;AAKO,SAAS,kBAAA,CAAmB,OAAA,GAA6B,EAAC,EAAW;AAC1E,EAAA,MAAM,QAAA,GAAW,oBAAoB,OAAO,CAAA;AAC5C,EAAA,OAAOA,IAAAA,CAAK,QAAA,CAAS,UAAA,EAAY,QAAQ,CAAA;AAC3C;AAKO,SAAS,gBAAA,CAAiB,OAAA,GAA6B,EAAC,EAAW;AACxE,EAAA,MAAM,QAAA,GAAW,oBAAoB,OAAO,CAAA;AAC5C,EAAA,OAAOA,IAAAA,CAAK,QAAA,CAAS,QAAA,EAAU,QAAQ,CAAA;AACzC;AAKO,SAAS,iBAAA,CAAkB,OAAA,GAA6B,EAAC,EAAW;AACzE,EAAA,MAAM,QAAA,GAAW,oBAAoB,OAAO,CAAA;AAC5C,EAAA,OAAOA,IAAAA,CAAK,QAAA,CAAS,SAAA,EAAW,QAAQ,CAAA;AAC1C;AAKO,SAAS,eAAA,CAAgB,GAAA,EAAoB,OAAA,GAA6B,EAAC,EAAW;AAC3F,EAAA,qBAAA,CAAsB,GAAG,CAAA;AACzB,EAAA,MAAM,YAAA,GAAe,mBAAmB,OAAO,CAAA;AAC/C,EAAA,OAAOA,IAAAA,CAAK,YAAA,EAAc,GAAA,CAAI,MAAA,EAAQ,IAAI,GAAG,CAAA;AAC/C;AAKO,SAAS,aAAA,CAAc,GAAA,EAAoB,OAAA,GAA6B,EAAC,EAAW;AACzF,EAAA,qBAAA,CAAsB,GAAG,CAAA;AACzB,EAAA,MAAM,UAAA,GAAa,iBAAiB,OAAO,CAAA;AAC3C,EAAA,OAAOA,IAAAA,CAAK,UAAA,EAAY,GAAA,CAAI,MAAA,EAAQ,IAAI,GAAG,CAAA;AAC7C;AAKO,SAAS,cAAA,CAAe,GAAA,EAAoB,OAAA,GAA6B,EAAC,EAAW;AAC1F,EAAA,qBAAA,CAAsB,GAAG,CAAA;AACzB,EAAA,MAAM,WAAA,GAAc,kBAAkB,OAAO,CAAA;AAC7C,EAAA,OAAOA,IAAAA,CAAK,WAAA,EAAa,GAAA,CAAI,MAAA,EAAQ,IAAI,GAAG,CAAA;AAC9C;AAKO,SAAS,oBAAA,CACd,GAAA,EACA,OAAA,GAA6B,EAAC,EACpB;AACV,EAAA,qBAAA,CAAsB,GAAG,CAAA;AAEzB,EAAA,MAAM,QAAkB,EAAC;AAGzB,EAAA,KAAA,CAAM,IAAA,CAAK,eAAA,CAAgB,GAAA,EAAK,OAAO,CAAC,CAAA;AAGxC,EAAA,KAAA,CAAM,IAAA,CAAK,kBAAA,CAAmB,OAAO,CAAC,CAAA;AAGtC,EAAA,IAAI,QAAQ,WAAA,EAAa;AACvB,IAAA,KAAA,MAAW,UAAA,IAAc,QAAQ,WAAA,EAAa;AAC5C,MAAA,MAAM,QAAA,GAAW,oBAAoB,OAAO,CAAA;AAC5C,MAAA,KAAA,CAAM,IAAA,CAAKA,IAAAA,CAAK,QAAA,CAAS,UAAA,EAAY,UAAU,CAAC,CAAA;AAAA,IAClD;AAAA,EACF;AAEA,EAAA,OAAO,KAAA;AACT;AAKA,eAAsB,gBAAgB,OAAA,EAAgC;AACpE,EAAA,MAAM,SAAA,GAAY,YAAY,GAAA,EAAI;AAElC,EAAA,IAAI;AACF,IAAA,MAAMQ,OAAO,OAAO,CAAA;AACpB,IAAA,OAAA,CAAQ,UAAU,gBAAgB,CAAA,CAAE,QAAQ,WAAA,CAAY,GAAA,KAAQ,SAAS,CAAA;AAAA,EAC3E,SAAS,KAAA,EAAO;AACd,IAAA,MAAM,SAAA,GAAY,KAAA;AAClB,IAAA,IAAI,SAAA,CAAU,SAAS,QAAA,EAAU;AAC/B,MAAA,IAAI;AACF,QAAA,MAAMC,KAAAA,CAAM,OAAA,EAAS,EAAE,SAAA,EAAW,MAAM,CAAA;AACxC,QAAA,OAAA,CAAQ,UAAU,gBAAgB,CAAA,CAAE,QAAQ,WAAA,CAAY,GAAA,KAAQ,SAAS,CAAA;AAAA,MAC3E,SAAS,UAAA,EAAY;AACnB,QAAA,OAAA,CAAQ,OAAA,CAAQ,oBAAoB,CAAA,CAAE,GAAA,EAAI;AAC1C,QAAA,OAAA,CAAQ,UAAU,gBAAgB,CAAA,CAAE,QAAQ,WAAA,CAAY,GAAA,KAAQ,SAAS,CAAA;AACzE,QAAA,MAAM,eAAA,CAAgB,uBAAA,CAAwB,OAAA,EAAS,UAAmB,CAAA;AAAA,MAC5E;AAAA,IACF,CAAA,MAAO;AACL,MAAA,OAAA,CAAQ,OAAA,CAAQ,oBAAoB,CAAA,CAAE,GAAA,EAAI;AAC1C,MAAA,OAAA,CAAQ,UAAU,gBAAgB,CAAA,CAAE,QAAQ,WAAA,CAAY,GAAA,KAAQ,SAAS,CAAA;AACzE,MAAA,MAAM,eAAA,CAAgB,uBAAA,CAAwB,OAAA,EAAS,SAAS,CAAA;AAAA,IAClE;AAAA,EACF;AACF;AAKA,eAAsB,iBAAA,CACpB,QAAA,EACA,WAAA,EACA,OAAA,GAAmC,EAAC,EACZ;AACxB,EAAA,MAAM,SAAA,GAAY,YAAY,GAAA,EAAI;AAElC,EAAA,IAAI;AACF,IAAA,KAAA,MAAW,cAAc,WAAA,EAAa;AACpC,MAAA,IAAI,QAAQ,SAAA,EAAW;AACrB,QAAA,MAAM,gBAAgB,UAAU,CAAA;AAAA,MAClC;AAEA,MAAA,MAAM,QAAA,GAAWT,IAAAA,CAAK,UAAA,EAAY,QAAQ,CAAA;AAC1C,MAAA,IAAI;AACF,QAAA,MAAMQ,OAAO,QAAQ,CAAA;AACrB,QAAA,OAAA,CAAQ,UAAU,gBAAgB,CAAA,CAAE,QAAQ,WAAA,CAAY,GAAA,KAAQ,SAAS,CAAA;AACzE,QAAA,OAAO,QAAA;AAAA,MACT,SAAS,KAAA,EAAO;AACd,QAAA,MAAM,SAAA,GAAY,KAAA;AAClB,QAAA,IAAI,SAAA,CAAU,SAAS,QAAA,EAAU;AAC/B,UAAA,OAAA,CAAQ,OAAA,CAAQ,oBAAoB,CAAA,CAAE,GAAA,EAAI;AAC1C,UAAA,OAAA,CAAQ,UAAU,gBAAgB,CAAA,CAAE,QAAQ,WAAA,CAAY,GAAA,KAAQ,SAAS,CAAA;AACzE,UAAA,MAAM,KAAA;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAEA,IAAA,OAAA,CAAQ,UAAU,gBAAgB,CAAA,CAAE,QAAQ,WAAA,CAAY,GAAA,KAAQ,SAAS,CAAA;AACzE,IAAA,OAAO,IAAA;AAAA,EACT,SAAS,KAAA,EAAO;AACd,IAAA,IAAI,EAAE,iBAAiB,eAAA,CAAA,EAAkB;AACvC,MAAA,OAAA,CAAQ,OAAA,CAAQ,oBAAoB,CAAA,CAAE,GAAA,EAAI;AAC1C,MAAA,OAAA,CAAQ,UAAU,gBAAgB,CAAA,CAAE,QAAQ,WAAA,CAAY,GAAA,KAAQ,SAAS,CAAA;AAAA,IAC3E;AACA,IAAA,MAAM,KAAA;AAAA,EACR;AACF;;;ADxLA,SAAS,SAAA,CAAU,QAAa,MAAA,EAAkB;AAChD,EAAA,IAAI,OAAO,MAAA,KAAW,QAAA,IAAY,MAAA,KAAW,IAAA,EAAM;AACjD,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA,EAAG;AACzB,IAAA,OAAO,gBAAgB,MAAM,CAAA;AAAA,EAC/B;AAEA,EAAA,IAAI,OAAO,WAAW,QAAA,IAAY,MAAA,KAAW,QAAQ,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA,EAAG;AAC1E,IAAA,OAAO,gBAAgB,MAAM,CAAA;AAAA,EAC/B;AAEA,EAAA,MAAM,MAAA,GAAS,EAAE,GAAG,MAAA,EAAO;AAE3B,EAAA,KAAA,MAAW,GAAA,IAAO,MAAA,CAAO,IAAA,CAAK,MAAM,CAAA,EAAG;AACrC,IAAA,IAAI,MAAA,CAAO,MAAA,CAAO,MAAA,EAAQ,GAAG,CAAA,EAAG;AAC9B,MAAA,IAAI,OAAO,MAAA,EAAQ;AACjB,QAAA,MAAA,CAAO,GAAG,IAAI,SAAA,CAAU,MAAA,CAAO,GAAG,CAAA,EAAG,MAAA,CAAO,GAAG,CAAC,CAAA;AAAA,MAClD,CAAA,MAAO;AACL,QAAA,MAAA,CAAO,GAAG,CAAA,GAAI,eAAA,CAAgB,MAAA,CAAO,GAAG,CAAC,CAAA;AAAA,MAC3C;AAAA,IACF;AAAA,EACF;AAEA,EAAA,OAAO,MAAA;AACT;AAMA,SAAS,cAAc,KAAA,EAAoB;AAEzC,EAAA,IAAI,KAAA,CAAM,WAAA,EAAY,KAAM,MAAA,EAAQ,OAAO,IAAA;AAC3C,EAAA,IAAI,KAAA,CAAM,WAAA,EAAY,KAAM,OAAA,EAAS,OAAO,KAAA;AAG5C,EAAA,IAAI,CAAC,MAAA,CAAO,KAAA,CAAM,MAAA,CAAO,KAAK,CAAC,CAAA,IAAK,KAAA,CAAM,IAAA,EAAK,KAAM,EAAA,EAAI;AACvD,IAAA,OAAO,OAAO,KAAK,CAAA;AAAA,EACrB;AAGA,EAAA,IAAI;AACF,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,KAAK,CAAA;AAC/B,IAAA,IAAI,OAAO,MAAA,KAAW,QAAA,IAAY,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA,EAAG;AACvD,MAAA,OAAO,MAAA;AAAA,IACT;AAAA,EACF,CAAA,CAAA,MAAQ;AAAA,EAER;AAEA,EAAA,OAAO,KAAA;AACT;AAMA,SAAS,aAAa,MAAA,EAAqB;AAEzC,EAAA,MAAM,SAAc,EAAC;AACrB,EAAA,MAAM,mBAAA,GAAsB,GAAG,MAAM,CAAA,CAAA,CAAA;AAErC,EAAA,KAAA,MAAW,CAAC,KAAK,KAAK,CAAA,IAAK,OAAO,OAAA,CAAQ,OAAA,CAAQ,GAAG,CAAA,EAAG;AACtD,IAAA,IAAI,CAAC,KAAA,EAAO;AAEZ,IAAA,IAAI,GAAA,CAAI,UAAA,CAAW,mBAAmB,CAAA,EAAG;AACvC,MAAA,MAAM,gBAAA,GAAmB,GAAA,CAAI,KAAA,CAAM,mBAAA,CAAoB,MAAM,CAAA;AAC7D,MAAA,MAAM,KAAA,GAAQ,gBAAA,CAAiB,KAAA,CAAM,GAAG,CAAA,CAAE,OAAO,CAAC,CAAA,KAAM,CAAA,CAAE,MAAA,GAAS,CAAC,CAAA;AAEpE,MAAA,IAAI,OAAA,GAAU,MAAA;AACd,MAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,CAAM,QAAQ,CAAA,EAAA,EAAK;AACrC,QAAA,MAAM,IAAA,GAAO,KAAA,CAAM,CAAC,CAAA,CAAE,WAAA,EAAY;AAGlC,QAAA,IAAI,CAAA,KAAM,KAAA,CAAM,MAAA,GAAS,CAAA,EAAG;AAC1B,UAAA,OAAA,CAAQ,IAAI,CAAA,GAAI,aAAA,CAAc,KAAK,CAAA;AAAA,QACrC,CAAA,MAAO;AAEL,UAAA,IAAI,CAAC,QAAQ,IAAI,CAAA,IAAK,OAAO,OAAA,CAAQ,IAAI,MAAM,QAAA,EAAU;AACvD,YAAA,OAAA,CAAQ,IAAI,IAAI,EAAC;AAAA,UACnB;AACA,UAAA,OAAA,GAAU,QAAQ,IAAI,CAAA;AAAA,QACxB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,EAAA,OAAO,MAAA;AACT;AAKA,SAAS,uBAAuB,MAAA,EAG9B;AAEA,EAAA,MAAM,SAAc,EAAC;AACrB,EAAA,MAAM,eAAyB,EAAC;AAChC,EAAA,MAAM,mBAAA,GAAsB,GAAG,MAAM,CAAA,CAAA,CAAA;AAErC,EAAA,KAAA,MAAW,CAAC,KAAK,KAAK,CAAA,IAAK,OAAO,OAAA,CAAQ,OAAA,CAAQ,GAAG,CAAA,EAAG;AACtD,IAAA,IAAI,CAAC,KAAA,EAAO;AAEZ,IAAA,IAAI,GAAA,CAAI,UAAA,CAAW,mBAAmB,CAAA,EAAG;AACvC,MAAA,YAAA,CAAa,KAAK,GAAG,CAAA;AAErB,MAAA,MAAM,gBAAA,GAAmB,GAAA,CAAI,KAAA,CAAM,mBAAA,CAAoB,MAAM,CAAA;AAC7D,MAAA,MAAM,KAAA,GAAQ,gBAAA,CAAiB,KAAA,CAAM,GAAG,CAAA,CAAE,OAAO,CAAC,CAAA,KAAM,CAAA,CAAE,MAAA,GAAS,CAAC,CAAA;AAEpE,MAAA,IAAI,OAAA,GAAU,MAAA;AACd,MAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,CAAM,QAAQ,CAAA,EAAA,EAAK;AACrC,QAAA,MAAM,IAAA,GAAO,KAAA,CAAM,CAAC,CAAA,CAAE,WAAA,EAAY;AAElC,QAAA,IAAI,CAAA,KAAM,KAAA,CAAM,MAAA,GAAS,CAAA,EAAG;AAC1B,UAAA,OAAA,CAAQ,IAAI,CAAA,GAAI,aAAA,CAAc,KAAK,CAAA;AAAA,QACrC,CAAA,MAAO;AACL,UAAA,IAAI,CAAC,QAAQ,IAAI,CAAA,IAAK,OAAO,OAAA,CAAQ,IAAI,MAAM,QAAA,EAAU;AACvD,YAAA,OAAA,CAAQ,IAAI,IAAI,EAAC;AAAA,UACnB;AACA,UAAA,OAAA,GAAU,QAAQ,IAAI,CAAA;AAAA,QACxB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,EAAA,YAAA,CAAa,IAAA,EAAK;AAClB,EAAA,OAAO,EAAE,QAAQ,YAAA,EAAa;AAChC;AAMA,eAAe,gBAAgB,IAAA,EAA4B;AACzD,EAAA,MAAM,OAAA,GAAU,MAAMP,QAAAA,CAAS,IAAA,EAAM,OAAO,CAAA;AAC5C,EAAA,MAAM,GAAA,GAAMS,OAAAA,CAAQ,IAAI,CAAA,CAAE,WAAA,EAAY;AAEtC,EAAA,IAAI,QAAQ,OAAA,EAAS;AACnB,IAAA,OAAO,IAAA,CAAK,MAAM,OAAO,CAAA;AAAA,EAC3B;AAEA,EAAA,IAAI,GAAA,KAAQ,OAAA,IAAW,GAAA,KAAQ,MAAA,EAAQ;AACrC,IAAA,OAAO,MAAM,OAAO,CAAA;AAAA,EACtB;AAEA,EAAA,MAAM,IAAI,KAAA,CAAM,CAAA,mCAAA,EAAsC,GAAG,CAAA,CAAE,CAAA;AAC7D;AAWA,eAAsB,WACpB,OAAA,EAC0B;AAC1B,EAAA,MAAM,EAAE,QAAA,EAAU,YAAA,EAAc,QAAA,EAAU,gBAAe,GAAI,OAAA;AAC7D,EAAA,MAAM,YAAA,GAAyB,CAAC,UAAU,CAAA;AAG1C,EAAA,IAAI,YAAA;AACJ,EAAA,IAAI,aAAa,MAAA,EAAW;AAE1B,IAAA,YAAA,GAAe,gBAAgB,QAAQ,CAAA;AAAA,EACzC,WAAW,YAAA,EAAc;AACvB,IAAA,YAAA,GAAe,MAAM,gBAAgB,YAAY,CAAA;AAAA,EACnD,CAAA,MAAO;AACL,IAAA,MAAM,IAAI,MAAM,kEAAkE,CAAA;AAAA,EACpF;AAGA,EAAA,MAAM,UAAA,GAAa,kBAAkB,QAAA,CAAS,GAAA;AAM9C,EAAA,MAAM,UAAA,GAAa,CAAC,OAAA,EAAS,MAAA,EAAQ,OAAO,CAAA;AAC5C,EAAA,IAAI,cAAA,GAAgC,IAAA;AAEpC,EAAA,MAAM,KAAA,GAAQ,qBAAqB,QAAQ,CAAA;AAE3C,EAAA,KAAA,MAAW,OAAO,UAAA,EAAY;AAC5B,IAAA,MAAM,QAAA,GAAW,CAAA,EAAG,UAAU,CAAA,EAAG,GAAG,CAAA,CAAA;AACpC,IAAA,MAAM,SAAA,GAAY,MAAM,iBAAA,CAAkB,QAAA,EAAU,KAAK,CAAA;AACzD,IAAA,IAAI,SAAA,EAAW;AACb,MAAA,cAAA,GAAiB,SAAA;AACjB,MAAA;AAAA,IACF;AAAA,EACF;AAEA,EAAA,IAAI,cAAA,EAAgB;AAClB,IAAA,MAAM,UAAA,GAAa,MAAM,eAAA,CAAgB,cAAc,CAAA;AACvD,IAAA,YAAA,GAAe,SAAA,CAAU,cAAc,UAAU,CAAA;AACjD,IAAA,YAAA,CAAa,KAAK,MAAM,CAAA;AAAA,EAC1B;AAGA,EAAA,MAAM,SAAA,GACJ,OAAA,CAAQ,SAAA,KAAc,QAAA,CAAS,GAAA,GAAM,QAAA,CAAS,GAAA,CAAI,WAAA,EAAY,CAAE,OAAA,CAAQ,IAAA,EAAM,GAAG,CAAA,GAAI,KAAA,CAAA;AAEvF,EAAA,MAAM,mBAAA,GAAsB,QAAQ,mBAAA,KAAwB,IAAA;AAC5D,EAAA,MAAM,OAAA,GAAU,mBAAA,GAAsB,sBAAA,CAAuB,SAAS,CAAA,GAAI,IAAA;AAC1E,EAAA,MAAM,SAAA,GAAY,mBAAA,GAAsB,OAAA,EAAS,MAAA,GAAS,aAAa,SAAS,CAAA;AAEhF,EAAA,IACE,SAAA,IACA,OAAO,SAAA,KAAc,QAAA,IACrB,OAAO,IAAA,CAAK,SAAoC,CAAA,CAAE,MAAA,GAAS,CAAA,EAC3D;AACA,IAAA,YAAA,GAAe,SAAA,CAAU,cAAc,SAAS,CAAA;AAChD,IAAA,YAAA,CAAa,KAAK,KAAK,CAAA;AAAA,EACzB;AAGA,EAAA,MAAM,cAAA,GAAiB,OAAA,CAAQ,MAAA,KAAW,MAAA,IAAa,QAAQ,UAAA,KAAe,MAAA;AAC9E,EAAA,IAAI,cAAA,EAAgB;AAClB,IAAA,IAAI;AACF,MAAA,MAAM,aAAA,GACJ,OAAA,CAAQ,MAAA,KAAW,KAAA,CAAA,GACf,OAAA,CAAQ,SACR,MAAMT,QAAAA,CAAS,OAAA,CAAQ,UAAA,EAAsB,OAAO,CAAA;AAC1D,MAAA,MAAM,SAAA,GAAY,MAAM,aAAA,CAAc,aAAa,CAAA;AACnD,MAAA,MAAM,MAAA,GAAS,YAAA,CAAa,YAAA,EAAc,SAAS,CAAA;AAEnD,MAAA,IAAI,CAAC,OAAO,KAAA,EAAO;AACjB,QAAA,MAAM,IAAI,qBAAA,CAAsB,iCAAA,EAAmC,MAAA,CAAO,WAAW,CAAA;AAAA,MACvF;AAAA,IAIF,SAAS,KAAA,EAAO;AACd,MAAA,IAAI,iBAAiB,qBAAA,EAAuB;AAC1C,QAAA,MAAM,KAAA;AAAA,MACR;AACA,MAAA,MAAM,IAAI,qBAAA;AAAA,QACR,CAAA,kCAAA,EAAsC,MAAgB,OAAO,CAAA,CAAA;AAAA,QAC7D,MAAA;AAAA,QACA;AAAA,OACF;AAAA,IACF;AAAA,EACF;AAEA,EAAA,OAAO;AAAA,IACL,MAAA,EAAQ,YAAA;AAAA,IACR,QAAA,EAAU;AAAA,MACR,YAAA,EAAc,QAAA,KAAa,MAAA,GAAY,EAAA,GAAM,YAAA;AAAA,MAC7C,cAAA,EAAgB,QAAA,KAAa,MAAA,GAAY,QAAA,GAAW,MAAA;AAAA,MACpD,cAAA;AAAA,MACA,SAAA;AAAA,MACA,eAAA,EAAiB,mBAAA,GAAsB,OAAA,EAAS,YAAA,GAAe,MAAA;AAAA,MAC/D,oBAAA,EAAsB,mBAAA,GAAsB,OAAA,EAAS,YAAA,CAAa,MAAA,GAAS,MAAA;AAAA,MAC3E,YAAA;AAAA,MACA,MAAA,EAAQ;AAAA;AAAA,QAEN,MAAM,OAAA,CAAQ,MAAA,KAAW,MAAA,GAAY,IAAA,GAAQ,QAAQ,UAAA,IAAc,IAAA;AAAA,QACnE,QAAQ,OAAA,CAAQ,MAAA,KAAW,SAAY,QAAA,GAAW,OAAA,CAAQ,aAAa,MAAA,GAAS,IAAA;AAAA,QAChF,SAAA,EAAW;AAAA;AACb;AACF,GACF;AACF;;;AE5bO,IAAM,OAAA,GAAU","file":"index.js","sourcesContent":["import type Ajv from \"ajv\";\nimport addFormats from \"ajv-formats\";\n\nexport interface FulmenAjvFormatsOptions {\n mode?: \"fast\" | \"full\";\n formats?: string[];\n}\n\nconst DEFAULT_FORMATS = [\n \"date-time\",\n \"email\",\n \"hostname\",\n \"ipv4\",\n \"ipv6\",\n \"uri\",\n \"uri-reference\",\n \"uuid\",\n];\n\n/**\n * Apply Fulmen-standard AJV format support.\n *\n * Useful when configuring AJV in other frameworks (e.g. Fastify) so JSON Schema\n * `format` keywords are enforced consistently.\n */\nexport function applyFulmenAjvFormats(ajv: Ajv, options: FulmenAjvFormatsOptions = {}): Ajv {\n const mode = options.mode ?? \"fast\";\n const formats = options.formats ?? DEFAULT_FORMATS;\n\n // ajv-formats types use a string-literal union; allow callers to supply strings.\n // The `as never` on ajv works around ajv-formats bundling its own older ajv types\n // that diverge from ajv@8.18+ (CodeKeywordDefinition.code parameter incompatibility).\n addFormats(ajv as never, { mode, formats: formats as unknown as never[] });\n return ajv;\n}\n","/**\n * Schema validation errors - implements Fulmen Schema Validation Standard\n */\n\nimport type { SchemaSource, SchemaValidationDiagnostic } from \"./types.js\";\n\n/**\n * Export error reason enum for type-safe error categorization\n */\nexport enum ExportErrorReason {\n FILE_EXISTS = \"FILE_EXISTS\",\n WRITE_FAILED = \"WRITE_FAILED\",\n INVALID_FORMAT = \"INVALID_FORMAT\",\n PROVENANCE_FAILED = \"PROVENANCE_FAILED\",\n UNKNOWN = \"UNKNOWN\",\n}\n\n/**\n * Base error class for schema validation operations\n */\nexport class SchemaValidationError extends Error {\n constructor(\n message: string,\n public schemaId?: string,\n public diagnostics: SchemaValidationDiagnostic[] = [],\n public source?: SchemaSource,\n public cause?: Error,\n ) {\n super(message);\n this.name = \"SchemaValidationError\";\n\n // Maintains proper stack trace for where our error was thrown (only available on V8)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, SchemaValidationError);\n }\n }\n\n /**\n * Create error for schema not found\n */\n static schemaNotFound(schemaId: string): SchemaValidationError {\n return new SchemaValidationError(`Schema not found: ${schemaId}`, schemaId);\n }\n\n /**\n * Create error for invalid schema input\n */\n static invalidSchemaInput(source: SchemaSource, details: string): SchemaValidationError {\n return new SchemaValidationError(`Invalid schema input: ${details}`, undefined, [], source);\n }\n\n /**\n * Create error for validation failure\n */\n static validationFailed(\n schemaId: string,\n diagnostics: SchemaValidationDiagnostic[],\n source?: SchemaSource,\n ): SchemaValidationError {\n const errorCount = diagnostics.filter((d) => d.severity === \"ERROR\").length;\n const warningCount = diagnostics.filter((d) => d.severity === \"WARN\").length;\n\n const message = `Schema validation failed: ${errorCount} error(s), ${warningCount} warning(s)`;\n\n return new SchemaValidationError(message, schemaId, diagnostics, source);\n }\n\n /**\n * Create error for goneat binary not found\n */\n static goneatNotFound(goneatPath?: string): SchemaValidationError {\n const pathInfo = goneatPath ? ` at ${goneatPath}` : \"\";\n return new SchemaValidationError(\n `Goneat binary not found${pathInfo}. Falling back to AJV validation.`,\n );\n }\n\n /**\n * Create error for goneat execution failure\n */\n static goneatExecutionFailed(error: Error): SchemaValidationError {\n return new SchemaValidationError(\n \"Goneat execution failed. Falling back to AJV validation.\",\n undefined,\n [],\n undefined,\n error,\n );\n }\n\n /**\n * Create error for empty schema input\n */\n static emptySchemaInput(source?: SchemaSource): SchemaValidationError {\n return new SchemaValidationError(\"Schema content is empty\", undefined, [], source);\n }\n\n /**\n * Create error for parse failure\n */\n static parseFailed(source: SchemaSource, error: Error): SchemaValidationError {\n return new SchemaValidationError(\n `Failed to parse schema: ${error.message}`,\n undefined,\n [],\n source,\n error,\n );\n }\n\n /**\n * Create error for encoding failure\n */\n static encodingFailed(source: SchemaSource, error: Error): SchemaValidationError {\n return new SchemaValidationError(\n `Failed to encode schema: ${error.message}`,\n undefined,\n [],\n source,\n error,\n );\n }\n\n /**\n * Create error for registry operation failure\n */\n static registryError(operation: string, details: string): SchemaValidationError {\n return new SchemaValidationError(`Schema registry ${operation} failed: ${details}`);\n }\n\n /**\n * Format error for display\n */\n format(): string {\n let output = this.message;\n\n if (this.schemaId) {\n output += `\\nSchema ID: ${this.schemaId}`;\n }\n\n if (this.diagnostics.length > 0) {\n output += \"\\n\\nValidation Issues:\";\n this.diagnostics.forEach((diag, index) => {\n output += `\\n ${index + 1}. [${diag.severity}] ${diag.message}`;\n if (diag.pointer) {\n output += ` at ${diag.pointer}`;\n }\n if (diag.keyword) {\n output += ` (keyword: ${diag.keyword})`;\n }\n if (diag.source) {\n output += ` [${diag.source}]`;\n }\n });\n }\n\n if (this.source) {\n output += `\\n\\nSource: ${this.source.type}`;\n if (this.source.id) {\n output += ` (${this.source.id})`;\n }\n }\n\n return output;\n }\n\n /**\n * Convert to JSON representation\n */\n toJSON(): {\n name: string;\n message: string;\n schemaId?: string;\n diagnostics: SchemaValidationDiagnostic[];\n source?: SchemaSource;\n cause?: string;\n } {\n return {\n name: this.name,\n message: this.message,\n schemaId: this.schemaId,\n diagnostics: this.diagnostics,\n source: this.source,\n cause: this.cause?.message,\n };\n }\n}\n\n/**\n * Error class for schema export operations\n */\nexport class SchemaExportError extends SchemaValidationError {\n constructor(\n message: string,\n public reason: ExportErrorReason,\n public schemaId?: string,\n public outPath?: string,\n public cause?: Error,\n ) {\n super(message, schemaId, [], undefined, cause);\n this.name = \"SchemaExportError\";\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, SchemaExportError);\n }\n }\n\n /**\n * Create error for file already exists\n */\n static fileExists(outPath: string): SchemaExportError {\n return new SchemaExportError(\n `Output file already exists: ${outPath}. Use overwrite option to replace.`,\n ExportErrorReason.FILE_EXISTS,\n undefined,\n outPath,\n );\n }\n\n /**\n * Create error for invalid export format\n */\n static invalidFormat(format: string, outPath: string): SchemaExportError {\n return new SchemaExportError(\n `Invalid export format: ${format}. Must be 'json' or 'yaml'.`,\n ExportErrorReason.INVALID_FORMAT,\n undefined,\n outPath,\n );\n }\n\n /**\n * Create error for write failure\n */\n static writeFailed(outPath: string, error: Error): SchemaExportError {\n return new SchemaExportError(\n `Failed to write schema to ${outPath}: ${error.message}`,\n ExportErrorReason.WRITE_FAILED,\n undefined,\n outPath,\n error,\n );\n }\n\n /**\n * Create error for provenance extraction failure\n */\n static provenanceFailed(details: string, error?: Error): SchemaExportError {\n return new SchemaExportError(\n `Failed to extract provenance metadata: ${details}`,\n ExportErrorReason.PROVENANCE_FAILED,\n undefined,\n undefined,\n error,\n );\n }\n}\n","/**\n * Schema validation utilities - helper functions for formatting and validation\n */\n\nimport { SchemaValidationError } from \"./errors.js\";\nimport type { SchemaValidationDiagnostic, SchemaValidationResult } from \"./types.js\";\n\n/**\n * Format validation diagnostics for display\n */\nexport function formatDiagnostics(diagnostics: SchemaValidationDiagnostic[]): string {\n if (diagnostics.length === 0) {\n return \"No validation issues found.\";\n }\n\n const lines: string[] = [];\n const errors = diagnostics.filter((d) => d.severity === \"ERROR\");\n const warnings = diagnostics.filter((d) => d.severity === \"WARN\");\n\n if (errors.length > 0) {\n lines.push(`❌ ${errors.length} error(s) found:`);\n errors.forEach((diag, index) => {\n lines.push(` ${index + 1}. ${diag.message}`);\n if (diag.pointer) {\n lines.push(` at ${diag.pointer}`);\n }\n if (diag.keyword) {\n lines.push(` keyword: ${diag.keyword}`);\n }\n });\n }\n\n if (warnings.length > 0) {\n lines.push(\"\");\n lines.push(`⚠️ ${warnings.length} warning(s) found:`);\n warnings.forEach((diag, index) => {\n lines.push(` ${index + 1}. ${diag.message}`);\n if (diag.pointer) {\n lines.push(` at ${diag.pointer}`);\n }\n });\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Format validation result for display\n */\nexport function formatValidationResult(result: SchemaValidationResult): string {\n if (result.valid) {\n return \"✅ Validation passed\";\n }\n\n const output: string[] = [];\n output.push(\"❌ Validation failed\");\n output.push(formatDiagnostics(result.diagnostics));\n output.push(`\\nSource: ${result.source}`);\n\n return output.join(\"\\n\");\n}\n\n/**\n * Check if value is a SchemaValidationError\n */\nexport function isValidationError(error: unknown): error is SchemaValidationError {\n return error instanceof SchemaValidationError;\n}\n\n/**\n * Extract validation result from error or return success\n */\nexport function extractValidationResult(error: unknown): {\n valid: boolean;\n diagnostics: SchemaValidationDiagnostic[];\n source: \"ajv\" | \"goneat\";\n} {\n if (isValidationError(error)) {\n return {\n valid: false,\n diagnostics: error.diagnostics,\n source: error.diagnostics[0]?.source || \"ajv\",\n };\n }\n\n return {\n valid: true,\n diagnostics: [],\n source: \"ajv\",\n };\n}\n\n/**\n * Normalize JSON pointer path for display\n */\nexport function normalizePointer(pointer: string): string {\n if (pointer === \"\") {\n return \"root\";\n }\n return pointer.replace(/^\\//, \"\").replace(/\\//g, \".\");\n}\n\n/**\n * Create a validation diagnostic\n */\nexport function createDiagnostic(\n pointer: string,\n message: string,\n keyword: string,\n severity: \"ERROR\" | \"WARN\" = \"ERROR\",\n source: \"ajv\" | \"goneat\" = \"ajv\",\n data?: unknown,\n): SchemaValidationDiagnostic {\n return {\n pointer,\n message,\n keyword,\n severity,\n source,\n data,\n };\n}\n\n/**\n * Group diagnostics by severity\n */\nexport function groupDiagnosticsBySeverity(diagnostics: SchemaValidationDiagnostic[]): {\n errors: SchemaValidationDiagnostic[];\n warnings: SchemaValidationDiagnostic[];\n} {\n return {\n errors: diagnostics.filter((d) => d.severity === \"ERROR\"),\n warnings: diagnostics.filter((d) => d.severity === \"WARN\"),\n };\n}\n\n/**\n * Count diagnostics by severity\n */\nexport function countDiagnostics(diagnostics: SchemaValidationDiagnostic[]): {\n total: number;\n errors: number;\n warnings: number;\n} {\n const grouped = groupDiagnosticsBySeverity(diagnostics);\n return {\n total: diagnostics.length,\n errors: grouped.errors.length,\n warnings: grouped.warnings.length,\n };\n}\n","/**\n * Goneat bridge - Optional integration for CLI-only goneat validation\n *\n * Provides goneat validation as an opt-in alternative for CLI exploration.\n * NOT used by library consumers - AJV validation is the primary implementation.\n */\n\nimport { spawn } from \"node:child_process\";\nimport { access } from \"node:fs/promises\";\nimport type { SchemaValidationDiagnostic, SchemaValidationResult } from \"./types.js\";\nimport { createDiagnostic } from \"./utils.js\";\n\n/**\n * Goneat validation output structure\n */\ninterface GoneatValidationOutput {\n valid: boolean;\n errors?: Array<{\n path: string;\n message: string;\n keyword?: string;\n }>;\n}\n\n/**\n * Detect goneat binary location\n */\nexport async function detectGoneat(customPath?: string): Promise<string | null> {\n // Try custom path first\n if (customPath) {\n try {\n await access(customPath);\n return customPath;\n } catch {\n return null;\n }\n }\n\n // Try GONEAT_PATH environment variable\n if (process.env.GONEAT_PATH) {\n try {\n await access(process.env.GONEAT_PATH);\n return process.env.GONEAT_PATH;\n } catch {\n // Continue to next option\n }\n }\n\n // Try local bin/goneat\n try {\n await access(\"./bin/goneat\");\n return \"./bin/goneat\";\n } catch {\n // Continue to next option\n }\n\n // Try system PATH (assume 'goneat' command available)\n return \"goneat\";\n}\n\n/**\n * Check if goneat is available\n *\n * If goneatPath is provided, use it directly to test availability.\n * Otherwise, detect goneat location first.\n */\nexport async function isGoneatAvailable(goneatPath?: string): Promise<boolean> {\n let pathToTest: string | null;\n\n if (goneatPath) {\n // Use provided path directly - don't re-detect\n // This allows testing 'goneat' command from PATH\n pathToTest = goneatPath;\n } else {\n // Detect goneat location\n pathToTest = await detectGoneat();\n if (!pathToTest) return false;\n }\n\n return new Promise((resolve) => {\n const proc = spawn(pathToTest as string, [\"version\"], { stdio: \"ignore\" });\n\n // Timeout after 5 seconds to prevent hanging in CI\n const timeout = setTimeout(() => {\n proc.kill();\n resolve(false);\n }, 5000);\n\n proc.on(\"close\", (code) => {\n clearTimeout(timeout);\n resolve(code === 0);\n });\n proc.on(\"error\", () => {\n clearTimeout(timeout);\n resolve(false);\n });\n });\n}\n\n/**\n * Run goneat schema validation (CLI-only, opt-in)\n *\n * This is NOT used by library validation - it's purely for CLI comparison.\n * Library users get full AJV validation without goneat dependency.\n */\nexport async function runGoneatValidation(\n schemaPath: string,\n dataPath: string,\n goneatPath?: string,\n): Promise<SchemaValidationResult> {\n const detected = await detectGoneat(goneatPath);\n\n if (!detected) {\n return {\n valid: false,\n diagnostics: [\n createDiagnostic(\n \"\",\n \"goneat binary not found. Install goneat or specify path with --goneat-path\",\n \"goneat-unavailable\",\n \"ERROR\",\n \"goneat\",\n ),\n ],\n source: \"goneat\",\n };\n }\n\n // Check availability using the detected path directly\n if (!(await isGoneatAvailable(detected))) {\n return {\n valid: false,\n diagnostics: [\n createDiagnostic(\n \"\",\n `goneat binary found at '${detected}' but not executable or version check failed`,\n \"goneat-not-executable\",\n \"ERROR\",\n \"goneat\",\n ),\n ],\n source: \"goneat\",\n };\n }\n\n return new Promise((resolve) => {\n const args = [\n \"schema\",\n \"validate\",\n \"--schema\",\n schemaPath,\n \"--data\",\n dataPath,\n \"--format\",\n \"json\",\n ];\n const proc = spawn(detected, args);\n\n let stdout = \"\";\n let stderr = \"\";\n\n proc.stdout.on(\"data\", (data) => {\n stdout += data.toString();\n });\n\n proc.stderr.on(\"data\", (data) => {\n stderr += data.toString();\n });\n\n proc.on(\"close\", (code: number | null) => {\n // Parse goneat output\n let output: GoneatValidationOutput;\n\n try {\n output = JSON.parse(stdout) as GoneatValidationOutput;\n } catch {\n // Failed to parse output, treat as error\n resolve({\n valid: false,\n diagnostics: [\n createDiagnostic(\n \"\",\n `goneat validation failed: ${stderr || \"unknown error\"}`,\n \"goneat-error\",\n \"ERROR\",\n \"goneat\",\n ),\n ],\n source: \"goneat\",\n });\n return;\n }\n\n // Convert goneat errors to our diagnostic format\n const diagnostics: SchemaValidationDiagnostic[] =\n output.errors?.map((error) =>\n createDiagnostic(\n error.path || \"\",\n error.message,\n error.keyword || \"validation\",\n \"ERROR\",\n \"goneat\",\n ),\n ) || [];\n\n resolve({\n valid: code === 0 && output.valid,\n diagnostics,\n source: \"goneat\",\n });\n });\n\n proc.on(\"error\", (error) => {\n resolve({\n valid: false,\n diagnostics: [\n createDiagnostic(\n \"\",\n `Failed to execute goneat: ${error.message}`,\n \"goneat-spawn-error\",\n \"ERROR\",\n \"goneat\",\n ),\n ],\n source: \"goneat\",\n });\n });\n });\n}\n","/**\n * Schema normalizer - implements schema normalization per Fulmen standard\n *\n * Provides utilities for canonicalizing and comparing schemas across\n * JSON and YAML formats with comment preservation and deterministic output.\n */\n\nimport { parse as parseYAML } from \"yaml\";\nimport { SchemaValidationError } from \"./errors.js\";\nimport type { SchemaInput, SchemaNormalizationOptions } from \"./types.js\";\n\n/**\n * Parse schema input to object\n */\nfunction parseSchemaInput(input: SchemaInput): Record<string, unknown> {\n if (!input) {\n throw SchemaValidationError.parseFailed(\n { type: \"string\", content: \"\" },\n new Error(\"schema content is empty\"),\n );\n }\n\n try {\n if (typeof input === \"string\") {\n // Try JSON first, fall back to YAML\n try {\n return JSON.parse(input) as Record<string, unknown>;\n } catch {\n return parseYAML(input) as Record<string, unknown>;\n }\n }\n\n if (Buffer.isBuffer(input)) {\n const content = input.toString(\"utf-8\");\n try {\n return JSON.parse(content) as Record<string, unknown>;\n } catch {\n return parseYAML(content) as Record<string, unknown>;\n }\n }\n\n // Already an object\n return input as Record<string, unknown>;\n } catch (error) {\n throw SchemaValidationError.parseFailed(\n {\n type: typeof input === \"string\" ? \"string\" : \"object\",\n content: typeof input === \"string\" ? input : JSON.stringify(input),\n },\n error as Error,\n );\n }\n}\n\n/**\n * Sort object keys recursively in lexicographical order\n */\nfunction sortObjectKeys(obj: unknown): unknown {\n if (obj === null || typeof obj !== \"object\") {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return obj.map(sortObjectKeys);\n }\n\n const sorted: Record<string, unknown> = {};\n const keys = Object.keys(obj).sort();\n\n for (const key of keys) {\n sorted[key] = sortObjectKeys((obj as Record<string, unknown>)[key]);\n }\n\n return sorted;\n}\n\n/**\n * Normalize schema to canonical JSON format\n *\n * Per Fulmen Schema Normalization Standard:\n * - Accepts YAML or JSON input\n * - Strips comments while preserving semantic structure\n * - Sorts keys lexicographically\n * - Produces deterministic, pretty-printed JSON (or compact if requested)\n */\nexport function normalizeSchema(\n input: SchemaInput,\n options: SchemaNormalizationOptions = {},\n): string {\n try {\n // Parse input to object\n const parsed = parseSchemaInput(input);\n\n // Sort keys recursively\n const sorted = sortObjectKeys(parsed);\n\n // Serialize to JSON with optional compact mode\n if (options.compact) {\n return JSON.stringify(sorted);\n }\n\n // Default: pretty-printed with 2-space indentation\n return JSON.stringify(sorted, null, 2);\n } catch (error) {\n if (error instanceof SchemaValidationError) {\n throw error;\n }\n throw SchemaValidationError.parseFailed(\n {\n type: typeof input === \"string\" ? \"string\" : \"object\",\n content: typeof input === \"string\" ? input : JSON.stringify(input),\n },\n error as Error,\n );\n }\n}\n\n/**\n * Compare two schemas for semantic equality\n *\n * Normalizes both schemas and compares the canonical JSON output.\n * Returns equality result along with normalized versions for debugging.\n */\nexport function compareSchemas(\n schemaA: SchemaInput,\n schemaB: SchemaInput,\n options: SchemaNormalizationOptions = {},\n): { equal: boolean; normalizedA: string; normalizedB: string } {\n const normalizedA = normalizeSchema(schemaA, options);\n const normalizedB = normalizeSchema(schemaB, options);\n\n return {\n equal: normalizedA === normalizedB,\n normalizedA,\n normalizedB,\n };\n}\n","/**\n * Schema registry - implements schema discovery and metadata extraction\n */\n\nimport { access, readFile } from \"node:fs/promises\";\nimport { dirname, extname, join, relative } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport glob from \"fast-glob\";\nimport { parse as parseYAML } from \"yaml\";\nimport { SchemaValidationError } from \"./errors.js\";\nimport type { SchemaFormat, SchemaMetadata, SchemaRegistryOptions } from \"./types.js\";\n\n/**\n * Default schema file patterns\n */\nconst DEFAULT_PATTERNS = [\"**/*.schema.json\", \"**/*.schema.yaml\", \"**/*.schema.yml\"];\n\n/**\n * Schema registry class for managing schema discovery and metadata\n */\nexport class SchemaRegistry {\n private schemas: Map<string, SchemaMetadata> = new Map();\n private options: SchemaRegistryOptions;\n\n constructor(options: SchemaRegistryOptions = {}) {\n this.options = {\n baseDir: options.baseDir || this.getDefaultSchemaDir(),\n patterns: options.patterns || DEFAULT_PATTERNS,\n followSymlinks: options.followSymlinks ?? false,\n maxDepth: options.maxDepth ?? 10,\n };\n }\n\n /**\n * Get default schema directory using import.meta.url\n */\n private getDefaultSchemaDir(): string {\n const __filename = fileURLToPath(import.meta.url);\n const __dirname = dirname(__filename);\n // From src/schema/ we need to go up 2 levels to repo root, then into schemas/crucible-ts\n return join(__dirname, \"..\", \"..\", \"schemas\", \"crucible-ts\");\n }\n\n /**\n * Build logical schema ID from file path\n */\n private buildSchemaId(filePath: string, baseDir: string): string {\n const relativePath = relative(baseDir, filePath);\n const withoutExt = relativePath.replace(/\\.(schema\\.(json|yaml|yml))$/, \"\");\n return withoutExt.replace(/\\\\/g, \"/\"); // Normalize path separators\n }\n\n /**\n * Extract schema format from file extension\n */\n private getSchemaFormat(filePath: string): SchemaFormat {\n const ext = extname(filePath).toLowerCase();\n switch (ext) {\n case \".json\":\n return \"json\";\n case \".yaml\":\n case \".yml\":\n return \"yaml\";\n default:\n return \"json\"; // Default fallback\n }\n }\n\n /**\n * Extract metadata from schema file\n */\n private async extractMetadata(filePath: string): Promise<SchemaMetadata> {\n try {\n const content = await readFile(filePath, \"utf-8\");\n const format = this.getSchemaFormat(filePath);\n\n let parsed: Record<string, unknown>;\n if (format === \"yaml\") {\n parsed = parseYAML(content) as Record<string, unknown>;\n } else {\n parsed = JSON.parse(content) as Record<string, unknown>;\n }\n\n const baseDir = this.options.baseDir ?? \"\";\n const relativePath = relative(baseDir, filePath);\n\n return {\n id: this.buildSchemaId(filePath, baseDir),\n path: filePath,\n relativePath: relativePath,\n format,\n version: (parsed.$schema as string) || (parsed.version as string),\n description: (parsed.title as string) || (parsed.description as string),\n schemaDraft: parsed.$schema as string,\n };\n } catch (error) {\n throw SchemaValidationError.registryError(\n \"metadata extraction\",\n `Failed to process ${filePath}: ${(error as Error).message}`,\n );\n }\n }\n\n /**\n * Discover and index all available schemas\n */\n async discoverSchemas(): Promise<void> {\n try {\n const baseDir = this.options.baseDir ?? \"\";\n const patterns = this.options.patterns ?? [];\n\n if (patterns.length === 0) {\n this.schemas.clear();\n return;\n }\n\n const pattern = patterns.map((p) => join(baseDir, p));\n\n // Check if base directory exists\n try {\n await access(baseDir);\n } catch {\n // Base directory doesn't exist, clear registry and return\n this.schemas.clear();\n return;\n }\n\n const files = await glob(pattern, {\n absolute: true,\n followSymbolicLinks: this.options.followSymlinks,\n deep: this.options.maxDepth,\n onlyFiles: true,\n suppressErrors: true, // Don't throw on permission errors\n });\n\n // Clear existing schemas\n this.schemas.clear();\n\n // Process each schema file\n for (const filePath of files) {\n try {\n const metadata = await this.extractMetadata(filePath);\n this.schemas.set(metadata.id, metadata);\n } catch (error) {\n // Log error but continue processing other schemas\n console.warn(`Warning: Failed to process schema ${filePath}:`, error);\n }\n }\n } catch (error) {\n throw SchemaValidationError.registryError(\"discovery\", (error as Error).message);\n }\n }\n\n /**\n * List available schemas with optional prefix filtering\n */\n async listSchemas(prefix?: string): Promise<SchemaMetadata[]> {\n if (this.schemas.size === 0) {\n await this.discoverSchemas();\n }\n\n const schemas = Array.from(this.schemas.values());\n\n if (prefix) {\n return schemas.filter((schema) => schema.id.startsWith(prefix));\n }\n\n return schemas;\n }\n\n /**\n * Get schema by logical ID\n */\n async getSchema(id: string): Promise<SchemaMetadata> {\n if (this.schemas.size === 0) {\n await this.discoverSchemas();\n }\n\n const schema = this.schemas.get(id);\n if (!schema) {\n throw SchemaValidationError.schemaNotFound(id);\n }\n\n return schema;\n }\n\n /**\n * Get schema by file path\n */\n async getSchemaByPath(filePath: string): Promise<SchemaMetadata> {\n if (this.schemas.size === 0) {\n await this.discoverSchemas();\n }\n\n const absolutePath = filePath.startsWith(\"/\") ? filePath : join(process.cwd(), filePath);\n\n for (const schema of this.schemas.values()) {\n if (schema.path === absolutePath) {\n return schema;\n }\n }\n\n throw SchemaValidationError.schemaNotFound(filePath);\n }\n\n /**\n * Check if schema exists\n */\n async hasSchema(id: string): Promise<boolean> {\n if (this.schemas.size === 0) {\n await this.discoverSchemas();\n }\n\n return this.schemas.has(id);\n }\n\n /**\n * Get registry size\n */\n get size(): number {\n return this.schemas.size;\n }\n\n /**\n * Clear registry cache\n */\n clear(): void {\n this.schemas.clear();\n }\n}\n\n/**\n * Global schema registry instance with cached options\n */\nlet globalRegistry: SchemaRegistry | undefined;\nlet globalRegistryOptions: SchemaRegistryOptions | undefined;\n\n/**\n * Check if registry options have changed\n */\nfunction optionsChanged(newOptions?: SchemaRegistryOptions): boolean {\n if (!newOptions && !globalRegistryOptions) return false;\n if (!newOptions || !globalRegistryOptions) return true;\n\n return (\n newOptions.baseDir !== globalRegistryOptions.baseDir ||\n JSON.stringify(newOptions.patterns) !== JSON.stringify(globalRegistryOptions.patterns) ||\n newOptions.followSymlinks !== globalRegistryOptions.followSymlinks ||\n newOptions.maxDepth !== globalRegistryOptions.maxDepth\n );\n}\n\n/**\n * Get or create global schema registry, rebuilding if options change\n */\nexport function getSchemaRegistry(options?: SchemaRegistryOptions): SchemaRegistry {\n if (!globalRegistry || optionsChanged(options)) {\n globalRegistry = new SchemaRegistry(options);\n globalRegistryOptions = options;\n }\n return globalRegistry;\n}\n\n/**\n * List available schemas with optional prefix filtering\n */\nexport async function listSchemas(\n prefix?: string,\n options?: SchemaRegistryOptions,\n): Promise<SchemaMetadata[]> {\n const registry = getSchemaRegistry(options);\n return registry.listSchemas(prefix);\n}\n\n/**\n * Get schema by logical ID\n */\nexport async function getSchema(\n id: string,\n options?: SchemaRegistryOptions,\n): Promise<SchemaMetadata> {\n const registry = getSchemaRegistry(options);\n return registry.getSchema(id);\n}\n\n/**\n * Get schema by file path\n */\nexport async function getSchemaByPath(\n filePath: string,\n options?: SchemaRegistryOptions,\n): Promise<SchemaMetadata> {\n const registry = getSchemaRegistry(options);\n return registry.getSchemaByPath(filePath);\n}\n\n/**\n * Check if schema exists\n */\nexport async function hasSchema(id: string, options?: SchemaRegistryOptions): Promise<boolean> {\n const registry = getSchemaRegistry(options);\n return registry.hasSchema(id);\n}\n","/**\n * Counter metric implementation\n *\n * Monotonically increasing counter for counting events\n */\n\nimport type { MetricName } from \"./types.js\";\n\n/**\n * Counter metric\n *\n * Monotonically increasing value for counting events.\n * Supports labeled metrics (Crucible v0.2.7+).\n * Use for metrics like request counts, error counts, etc.\n */\nexport class Counter {\n private value = 0;\n private labeledValues = new Map<string, number>();\n\n constructor(public readonly name: MetricName) {}\n\n /**\n * Increment counter by delta (default: 1)\n *\n * @param delta - Amount to increment (must be non-negative)\n * @param labels - Optional label dimensions for this observation\n * @throws {Error} If delta is negative\n *\n * @example\n * ```typescript\n * counter.inc(); // Increment unlabeled by 1\n * counter.inc(5); // Increment unlabeled by 5\n * counter.inc(1, { status: '200' }); // Increment labeled instance\n * counter.inc(1, { result: 'success' }); // Different label set\n * ```\n */\n inc(delta = 1, labels?: Record<string, string>): void {\n if (delta < 0) {\n throw new Error(`Counter delta must be non-negative, got: ${delta}`);\n }\n\n if (labels && Object.keys(labels).length > 0) {\n // Labeled metric - track per label combination\n const labelKey = this.serializeLabels(labels);\n const current = this.labeledValues.get(labelKey) || 0;\n this.labeledValues.set(labelKey, current + delta);\n } else {\n // Unlabeled metric\n this.value += delta;\n }\n }\n\n /**\n * Get current counter value (unlabeled)\n */\n getValue(): number {\n return this.value;\n }\n\n /**\n * Get all labeled values\n * @returns Map of serialized label keys to values\n */\n getLabeledValues(): Map<string, number> {\n return new Map(this.labeledValues);\n }\n\n /**\n * Get value for specific label combination\n */\n getValueForLabels(labels: Record<string, string>): number {\n const labelKey = this.serializeLabels(labels);\n return this.labeledValues.get(labelKey) || 0;\n }\n\n /**\n * Reset counter to zero (all label combinations)\n */\n reset(): void {\n this.value = 0;\n this.labeledValues.clear();\n }\n\n /**\n * Serialize labels to deterministic string key\n * Format: key1=value1,key2=value2 (sorted by key)\n */\n private serializeLabels(labels: Record<string, string>): string {\n return Object.entries(labels)\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([k, v]) => `${k}=${v}`)\n .join(\",\");\n }\n}\n","/**\n * Gauge metric implementation\n *\n * Gauge for arbitrary values that can go up and down\n */\n\nimport type { MetricName } from \"./types.js\";\n\n/**\n * Gauge metric\n *\n * Arbitrary value that can increase or decrease.\n * Supports labeled metrics (Crucible v0.2.7+).\n * Use for metrics like current connections, memory usage, temperature, etc.\n */\nexport class Gauge {\n private value = 0;\n private labeledValues = new Map<string, number>();\n\n constructor(public readonly name: MetricName) {}\n\n /**\n * Set gauge to specific value\n *\n * @param value - New gauge value (can be any number, including negative)\n * @param labels - Optional label dimensions for this observation\n *\n * @example\n * ```typescript\n * gauge.set(42); // Set unlabeled to 42\n * gauge.set(-10); // Negative values allowed\n * gauge.set(1, { phase: 'collect' }); // Set labeled instance\n * ```\n */\n set(value: number, labels?: Record<string, string>): void {\n if (labels && Object.keys(labels).length > 0) {\n const labelKey = this.serializeLabels(labels);\n this.labeledValues.set(labelKey, value);\n } else {\n this.value = value;\n }\n }\n\n /**\n * Increment gauge by delta (default: 1)\n *\n * @param delta - Amount to increment (can be negative)\n * @param labels - Optional label dimensions for this observation\n */\n inc(delta = 1, labels?: Record<string, string>): void {\n if (labels && Object.keys(labels).length > 0) {\n const labelKey = this.serializeLabels(labels);\n const current = this.labeledValues.get(labelKey) || 0;\n this.labeledValues.set(labelKey, current + delta);\n } else {\n this.value += delta;\n }\n }\n\n /**\n * Decrement gauge by delta (default: 1)\n *\n * @param delta - Amount to decrement (can be negative)\n * @param labels - Optional label dimensions for this observation\n */\n dec(delta = 1, labels?: Record<string, string>): void {\n if (labels && Object.keys(labels).length > 0) {\n const labelKey = this.serializeLabels(labels);\n const current = this.labeledValues.get(labelKey) || 0;\n this.labeledValues.set(labelKey, current - delta);\n } else {\n this.value -= delta;\n }\n }\n\n /**\n * Get current gauge value (unlabeled)\n */\n getValue(): number {\n return this.value;\n }\n\n /**\n * Get all labeled values\n * @returns Map of serialized label keys to values\n */\n getLabeledValues(): Map<string, number> {\n return new Map(this.labeledValues);\n }\n\n /**\n * Get value for specific label combination\n */\n getValueForLabels(labels: Record<string, string>): number {\n const labelKey = this.serializeLabels(labels);\n return this.labeledValues.get(labelKey) || 0;\n }\n\n /**\n * Reset gauge to zero (all label combinations)\n */\n reset(): void {\n this.value = 0;\n this.labeledValues.clear();\n }\n\n /**\n * Serialize labels to deterministic string key\n * Format: key1=value1,key2=value2 (sorted by key)\n */\n private serializeLabels(labels: Record<string, string>): string {\n return Object.entries(labels)\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([k, v]) => `${k}=${v}`)\n .join(\",\");\n }\n}\n","/**\n * Taxonomy loader for metrics definitions\n *\n * Loads and caches metrics taxonomy from config/crucible-ts/taxonomy/metrics.yaml\n * Provides default histogram buckets per ADR-0007\n */\n\nimport { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { parse as parseYaml } from \"yaml\";\nimport type { MetricName, MetricUnit } from \"./types.js\";\n\n/**\n * Metric definition from taxonomy\n */\nexport interface MetricDefinition {\n name: MetricName;\n unit: MetricUnit;\n description: string;\n}\n\n/**\n * Taxonomy structure\n */\nexport interface MetricsTaxonomy {\n version: string;\n defaults: {\n histogram_buckets: {\n ms_metrics: number[];\n };\n };\n metrics: MetricDefinition[];\n}\n\n/**\n * Default histogram buckets for _ms metrics (ADR-0007)\n * [1, 5, 10, 50, 100, 500, 1000, 5000, 10000] milliseconds\n */\nexport const DEFAULT_MS_BUCKETS = [1, 5, 10, 50, 100, 500, 1000, 5000, 10000];\n\n/**\n * Singleton taxonomy loader\n */\nclass TaxonomyLoader {\n private static instance: TaxonomyLoader;\n private taxonomy: MetricsTaxonomy | null = null;\n private loadPromise: Promise<MetricsTaxonomy> | null = null;\n private loadError: Error | null = null;\n\n private constructor() {\n // Private constructor for singleton\n }\n\n /**\n * Get singleton instance\n */\n static getInstance(): TaxonomyLoader {\n if (!TaxonomyLoader.instance) {\n TaxonomyLoader.instance = new TaxonomyLoader();\n }\n return TaxonomyLoader.instance;\n }\n\n /**\n * Load taxonomy from YAML file\n */\n private async load(): Promise<MetricsTaxonomy> {\n if (this.taxonomy !== null) {\n return this.taxonomy;\n }\n\n if (this.loadError !== null) {\n throw this.loadError;\n }\n\n if (this.loadPromise) {\n return this.loadPromise;\n }\n\n this.loadPromise = (async () => {\n try {\n // Resolve path to taxonomy file\n // From src/telemetry/ → ../../config/crucible-ts/taxonomy/metrics.yaml\n const taxonomyPath = join(\n __dirname,\n \"..\",\n \"..\",\n \"config\",\n \"crucible-ts\",\n \"taxonomy\",\n \"metrics.yaml\",\n );\n\n const content = await readFile(taxonomyPath, \"utf-8\");\n this.taxonomy = parseYaml(content) as MetricsTaxonomy;\n\n return this.taxonomy;\n } catch (err) {\n this.loadError = err instanceof Error ? err : new Error(String(err));\n throw new Error(`Failed to load metrics taxonomy: ${this.loadError.message}`);\n }\n })();\n\n return this.loadPromise;\n }\n\n /**\n * Get taxonomy (async)\n */\n async getTaxonomy(): Promise<MetricsTaxonomy> {\n return this.load();\n }\n\n /**\n * Get metric definition by name\n */\n async getMetric(name: MetricName): Promise<MetricDefinition | undefined> {\n const taxonomy = await this.load();\n return taxonomy.metrics.find((m) => m.name === name);\n }\n\n /**\n * Get default unit for metric\n */\n async getDefaultUnit(name: MetricName): Promise<MetricUnit | undefined> {\n const metric = await this.getMetric(name);\n return metric?.unit;\n }\n\n /**\n * Get default histogram buckets for metric\n * Returns ADR-0007 buckets for _ms metrics, undefined for others\n */\n async getDefaultBuckets(name: MetricName): Promise<number[] | undefined> {\n // Check if metric name ends with _ms\n if (name.endsWith(\"_ms\")) {\n const taxonomy = await this.load();\n return taxonomy.defaults.histogram_buckets.ms_metrics;\n }\n return undefined;\n }\n\n /**\n * Check if metric name is valid (exists in taxonomy)\n */\n async isValidMetricName(name: string): Promise<boolean> {\n try {\n const taxonomy = await this.load();\n return taxonomy.metrics.some((m) => m.name === name);\n } catch {\n return false;\n }\n }\n\n /**\n * Reset loader state (for testing)\n * @internal\n */\n static _reset(): void {\n TaxonomyLoader.instance = new TaxonomyLoader();\n }\n}\n\n/**\n * Get metrics taxonomy\n *\n * @returns Promise resolving to taxonomy\n */\nexport async function getTaxonomy(): Promise<MetricsTaxonomy> {\n return TaxonomyLoader.getInstance().getTaxonomy();\n}\n\n/**\n * Get metric definition by name\n *\n * @param name - Metric name\n * @returns Promise resolving to metric definition or undefined\n */\nexport async function getMetric(name: MetricName): Promise<MetricDefinition | undefined> {\n return TaxonomyLoader.getInstance().getMetric(name);\n}\n\n/**\n * Get default unit for metric from taxonomy\n *\n * @param name - Metric name\n * @returns Promise resolving to unit or undefined\n */\nexport async function getDefaultUnit(name: MetricName): Promise<MetricUnit | undefined> {\n return TaxonomyLoader.getInstance().getDefaultUnit(name);\n}\n\n/**\n * Get default histogram buckets for metric\n *\n * Returns ADR-0007 buckets ([1, 5, 10, 50, 100, 500, 1000, 5000, 10000]) for\n * metrics ending with _ms, undefined for others.\n *\n * @param name - Metric name\n * @returns Promise resolving to bucket array or undefined\n *\n * @example\n * ```typescript\n * const buckets = await getDefaultBuckets('config_load_ms');\n * // Returns [1, 5, 10, 50, 100, 500, 1000, 5000, 10000]\n * ```\n */\nexport async function getDefaultBuckets(name: MetricName): Promise<number[] | undefined> {\n return TaxonomyLoader.getInstance().getDefaultBuckets(name);\n}\n\n/**\n * Check if metric name is valid (exists in taxonomy)\n *\n * @param name - Metric name to check\n * @returns Promise resolving to true if valid\n */\nexport async function isValidMetricName(name: string): Promise<boolean> {\n return TaxonomyLoader.getInstance().isValidMetricName(name);\n}\n\n// Export for testing\nexport { TaxonomyLoader };\n","/**\n * Histogram metric implementation\n *\n * Histogram with OTLP-compatible cumulative buckets, auto-applying ADR-0007\n * default buckets for _ms metrics.\n */\n\nimport { DEFAULT_MS_BUCKETS } from \"./taxonomy.js\";\nimport type { HistogramBucket, HistogramOptions, HistogramSummary, MetricName } from \"./types.js\";\n\n/**\n * Labeled histogram state\n */\ninterface LabeledHistogramState {\n count: number;\n sum: number;\n bucketCounts: Map<number, number>;\n}\n\n/**\n * Histogram metric\n *\n * Tracks distribution of values using cumulative buckets (OTLP-compatible).\n * Automatically applies ADR-0007 default buckets for _ms metrics.\n * Supports labeled metrics (Crucible v0.2.7+).\n */\nexport class Histogram {\n private count = 0;\n private sum = 0;\n private bucketCounts: Map<number, number> = new Map();\n private labeledStates = new Map<string, LabeledHistogramState>();\n private readonly buckets: number[];\n\n constructor(\n public readonly name: MetricName,\n options?: HistogramOptions,\n ) {\n // Determine buckets: custom > ADR-0007 defaults for _ms metrics > empty\n if (options?.buckets) {\n this.buckets = [...options.buckets].sort((a, b) => a - b);\n } else if (name.endsWith(\"_ms\") || name.endsWith(\"_seconds\")) {\n this.buckets = [...DEFAULT_MS_BUCKETS];\n } else {\n this.buckets = [];\n }\n\n // Initialize bucket counts\n for (const bucket of this.buckets) {\n this.bucketCounts.set(bucket, 0);\n }\n }\n\n /**\n * Record an observation\n *\n * @param value - Value to observe (typically a duration in ms or seconds)\n * @param labels - Optional label dimensions for this observation\n *\n * @example\n * ```typescript\n * const start = performance.now();\n * // ... operation ...\n * histogram.observe(performance.now() - start);\n * histogram.observe(duration, { phase: 'collect', result: 'success' });\n * ```\n */\n observe(value: number, labels?: Record<string, string>): void {\n if (labels && Object.keys(labels).length > 0) {\n // Labeled observation\n const labelKey = this.serializeLabels(labels);\n let state = this.labeledStates.get(labelKey);\n\n if (!state) {\n // Initialize new labeled state\n state = {\n count: 0,\n sum: 0,\n bucketCounts: new Map(),\n };\n for (const bucket of this.buckets) {\n state.bucketCounts.set(bucket, 0);\n }\n this.labeledStates.set(labelKey, state);\n }\n\n state.count++;\n state.sum += value;\n\n // Update cumulative bucket counts\n for (const bucket of this.buckets) {\n if (value <= bucket) {\n state.bucketCounts.set(bucket, (state.bucketCounts.get(bucket) || 0) + 1);\n }\n }\n } else {\n // Unlabeled observation\n this.count++;\n this.sum += value;\n\n // Update cumulative bucket counts\n for (const bucket of this.buckets) {\n if (value <= bucket) {\n this.bucketCounts.set(bucket, (this.bucketCounts.get(bucket) || 0) + 1);\n }\n }\n }\n }\n\n /**\n * Get histogram summary\n *\n * Returns OTLP-compatible histogram summary with cumulative bucket counts.\n */\n getSummary(): HistogramSummary {\n const buckets: HistogramBucket[] = this.buckets.map((le) => ({\n le,\n count: this.bucketCounts.get(le) || 0,\n }));\n\n return {\n count: this.count,\n sum: this.sum,\n buckets,\n };\n }\n\n /**\n * Get current observation count\n */\n getCount(): number {\n return this.count;\n }\n\n /**\n * Get sum of all observed values\n */\n getSum(): number {\n return this.sum;\n }\n\n /**\n * Get average of observed values\n */\n getAverage(): number {\n return this.count > 0 ? this.sum / this.count : 0;\n }\n\n /**\n * Get all labeled summaries\n * @returns Map of serialized label keys to histogram summaries\n */\n getLabeledSummaries(): Map<string, HistogramSummary> {\n const summaries = new Map<string, HistogramSummary>();\n\n for (const [labelKey, state] of this.labeledStates) {\n const buckets: HistogramBucket[] = this.buckets.map((le) => ({\n le,\n count: state.bucketCounts.get(le) || 0,\n }));\n\n summaries.set(labelKey, {\n count: state.count,\n sum: state.sum,\n buckets,\n });\n }\n\n return summaries;\n }\n\n /**\n * Get summary for specific label combination\n */\n getSummaryForLabels(labels: Record<string, string>): HistogramSummary | null {\n const labelKey = this.serializeLabels(labels);\n const state = this.labeledStates.get(labelKey);\n\n if (!state) {\n return null;\n }\n\n const buckets: HistogramBucket[] = this.buckets.map((le) => ({\n le,\n count: state.bucketCounts.get(le) || 0,\n }));\n\n return {\n count: state.count,\n sum: state.sum,\n buckets,\n };\n }\n\n /**\n * Reset histogram to initial state (all label combinations)\n */\n reset(): void {\n this.count = 0;\n this.sum = 0;\n for (const bucket of this.buckets) {\n this.bucketCounts.set(bucket, 0);\n }\n this.labeledStates.clear();\n }\n\n /**\n * Serialize labels to deterministic string key\n * Format: key1=value1,key2=value2 (sorted by key)\n */\n private serializeLabels(labels: Record<string, string>): string {\n return Object.entries(labels)\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([k, v]) => `${k}=${v}`)\n .join(\",\");\n }\n}\n","/**\n * Metrics registry - central registry for all metrics\n *\n * Provides singleton registry for counters, gauges, and histograms.\n * Exports events in schema-compliant format.\n */\n\nimport { Counter } from \"./counter.js\";\nimport { Gauge } from \"./gauge.js\";\nimport { Histogram } from \"./histogram.js\";\nimport { getDefaultUnit } from \"./taxonomy.js\";\nimport type { FlushOptions, HistogramOptions, MetricName, MetricsEvent } from \"./types.js\";\n\n/**\n * Metrics registry\n *\n * Central registry for all metrics. Provides factory methods for counters,\n * gauges, and histograms. Exports metrics as schema-compliant events.\n */\nexport class MetricsRegistry {\n private counters: Map<MetricName, Counter> = new Map();\n private gauges: Map<MetricName, Gauge> = new Map();\n private histograms: Map<MetricName, Histogram> = new Map();\n\n /**\n * Get or create a counter\n *\n * @param name - Metric name from taxonomy\n * @returns Counter instance\n *\n * @example\n * ```typescript\n * const counter = registry.counter('schema_validations');\n * counter.inc();\n * ```\n */\n counter(name: MetricName): Counter {\n let counter = this.counters.get(name);\n if (!counter) {\n counter = new Counter(name);\n this.counters.set(name, counter);\n }\n return counter;\n }\n\n /**\n * Get or create a gauge\n *\n * @param name - Metric name from taxonomy\n * @returns Gauge instance\n *\n * @example\n * ```typescript\n * const gauge = registry.gauge('foundry_lookup_count');\n * gauge.set(42);\n * ```\n */\n gauge(name: MetricName): Gauge {\n let gauge = this.gauges.get(name);\n if (!gauge) {\n gauge = new Gauge(name);\n this.gauges.set(name, gauge);\n }\n return gauge;\n }\n\n /**\n * Get or create a histogram\n *\n * @param name - Metric name from taxonomy\n * @param options - Optional histogram options\n * @returns Histogram instance\n *\n * @example\n * ```typescript\n * // Auto-applies ADR-0007 buckets for _ms metrics\n * const histogram = registry.histogram('config_load_ms');\n * histogram.observe(42.5);\n *\n * // Custom buckets\n * const custom = registry.histogram('custom_metric', {\n * buckets: [10, 50, 100, 500, 1000]\n * });\n * ```\n */\n histogram(name: MetricName, options?: HistogramOptions): Histogram {\n let histogram = this.histograms.get(name);\n if (!histogram) {\n histogram = new Histogram(name, options);\n this.histograms.set(name, histogram);\n }\n return histogram;\n }\n\n /**\n * Export all metrics as events\n *\n * Returns array of schema-compliant MetricsEvent objects.\n * Does not clear metrics (use flush() to clear after export).\n *\n * @returns Promise resolving to array of metrics events\n *\n * @example\n * ```typescript\n * const events = await registry.export();\n * console.log(JSON.stringify(events, null, 2));\n * ```\n */\n async export(): Promise<MetricsEvent[]> {\n const events: MetricsEvent[] = [];\n const timestamp = new Date().toISOString();\n\n // Export counters (unlabeled + labeled) - Crucible v0.2.7+\n for (const [name, counter] of this.counters) {\n const unit = await getDefaultUnit(name);\n\n // Always export unlabeled value (for backwards compatibility)\n events.push({\n timestamp,\n name,\n value: counter.getValue(),\n unit,\n });\n\n // Export labeled values (only if > 0)\n for (const [labelKey, value] of counter.getLabeledValues()) {\n if (value > 0) {\n const tags = this.deserializeLabels(labelKey);\n events.push({\n timestamp,\n name,\n value,\n tags,\n unit,\n });\n }\n }\n }\n\n // Export gauges (unlabeled + labeled) - Crucible v0.2.7+\n for (const [name, gauge] of this.gauges) {\n const unit = await getDefaultUnit(name);\n\n // Export unlabeled value (always export gauges, even if zero)\n events.push({\n timestamp,\n name,\n value: gauge.getValue(),\n unit,\n });\n\n // Export labeled values\n for (const [labelKey, value] of gauge.getLabeledValues()) {\n const tags = this.deserializeLabels(labelKey);\n events.push({\n timestamp,\n name,\n value,\n tags,\n unit,\n });\n }\n }\n\n // Export histograms (unlabeled + labeled) - Crucible v0.2.7+\n for (const [name, histogram] of this.histograms) {\n const unit = await getDefaultUnit(name);\n\n // Always export unlabeled summary (for backwards compatibility)\n events.push({\n timestamp,\n name,\n value: histogram.getSummary(),\n unit,\n });\n\n // Export labeled summaries (only if count > 0)\n for (const [labelKey, summary] of histogram.getLabeledSummaries()) {\n if (summary.count > 0) {\n const tags = this.deserializeLabels(labelKey);\n events.push({\n timestamp,\n name,\n value: summary,\n tags,\n unit,\n });\n }\n }\n }\n\n return events;\n }\n\n /**\n * Deserialize label key back to tags object\n * Format: key1=value1,key2=value2 → {key1: \"value1\", key2: \"value2\"}\n */\n private deserializeLabels(labelKey: string): Record<string, string> {\n if (!labelKey) {\n return {};\n }\n\n const tags: Record<string, string> = {};\n for (const pair of labelKey.split(\",\")) {\n const [key, value] = pair.split(\"=\");\n if (key && value) {\n tags[key] = value;\n }\n }\n return tags;\n }\n\n /**\n * Export and clear all metrics\n *\n * Exports metrics as events, optionally emits them via logger,\n * then resets all metrics to zero.\n *\n * @param options - Flush options\n * @returns Promise resolving to array of exported events\n *\n * @example\n * ```typescript\n * // Export and clear\n * const events = await registry.flush();\n *\n * // Export, emit to logger, and clear\n * const events = await registry.flush({\n * emit: (events) => console.log(JSON.stringify(events))\n * });\n * ```\n */\n async flush(options?: FlushOptions): Promise<MetricsEvent[]> {\n const events = await this.export();\n\n try {\n // Emit if logger provided\n if (options?.emit) {\n options.emit(events);\n }\n } finally {\n // Always clear metrics, even if emit throws\n this.clear();\n }\n\n return events;\n }\n\n /**\n * Clear all metrics (reset to zero)\n *\n * Resets all counters, gauges, and histograms to their initial state.\n */\n clear(): void {\n for (const counter of this.counters.values()) {\n counter.reset();\n }\n for (const gauge of this.gauges.values()) {\n gauge.reset();\n }\n for (const histogram of this.histograms.values()) {\n histogram.reset();\n }\n }\n\n /**\n * Get all registered metric names\n *\n * Returns array of all metric names that have been accessed\n * (counters, gauges, or histograms).\n */\n getMetricNames(): MetricName[] {\n const names = new Set<MetricName>();\n for (const name of this.counters.keys()) {\n names.add(name);\n }\n for (const name of this.gauges.keys()) {\n names.add(name);\n }\n for (const name of this.histograms.keys()) {\n names.add(name);\n }\n return Array.from(names);\n }\n\n /**\n * Get total count of registered metrics\n */\n getMetricCount(): number {\n return this.counters.size + this.gauges.size + this.histograms.size;\n }\n}\n","/**\n * Telemetry types - TypeScript types for metrics events\n *\n * Based on schemas/crucible-ts/observability/metrics/v1.0.0/metrics-event.schema.json\n * and config/crucible-ts/taxonomy/metrics.yaml\n */\n\n/**\n * Metric name from taxonomy\n * Aligned with config/crucible-ts/taxonomy/metrics.yaml#/$defs/metricName\n * Updated for Crucible v0.2.18 (HTTP server metrics)\n */\nexport type MetricName =\n // Core module metrics\n | \"schema_validations\"\n | \"schema_validation_errors\"\n | \"config_load_ms\"\n | \"config_load_errors\"\n | \"pathfinder_find_ms\"\n | \"pathfinder_validation_errors\"\n | \"pathfinder_security_warnings\"\n | \"foundry_lookup_count\"\n | \"logging_emit_count\"\n | \"logging_emit_latency_ms\"\n | \"goneat_command_duration_ms\"\n // Prometheus exporter metrics\n | \"prometheus_exporter_refresh_duration_seconds\"\n | \"prometheus_exporter_refresh_total\"\n | \"prometheus_exporter_refresh_errors_total\"\n | \"prometheus_exporter_refresh_inflight\"\n | \"prometheus_exporter_http_requests_total\"\n | \"prometheus_exporter_http_errors_total\"\n | \"prometheus_exporter_restarts_total\"\n // Foundry MIME detection metrics\n | \"foundry_mime_detections_total_json\"\n | \"foundry_mime_detections_total_xml\"\n | \"foundry_mime_detections_total_yaml\"\n | \"foundry_mime_detections_total_csv\"\n | \"foundry_mime_detections_total_plain_text\"\n | \"foundry_mime_detections_total_unknown\"\n | \"foundry_mime_detection_ms_json\"\n | \"foundry_mime_detection_ms_xml\"\n | \"foundry_mime_detection_ms_yaml\"\n | \"foundry_mime_detection_ms_csv\"\n | \"foundry_mime_detection_ms_plain_text\"\n | \"foundry_mime_detection_ms_unknown\"\n // Error handling metrics\n | \"error_handling_wraps_total\"\n | \"error_handling_wrap_ms\"\n // FulHash metrics\n | \"fulhash_operations_total_xxh3_128\"\n | \"fulhash_operations_total_sha256\"\n | \"fulhash_hash_string_total\"\n | \"fulhash_bytes_hashed_total\"\n | \"fulhash_operation_ms\"\n // HTTP server metrics (v0.2.18)\n | \"http_requests_total\"\n | \"http_request_duration_seconds\"\n | \"http_request_size_bytes\"\n | \"http_response_size_bytes\"\n | \"http_active_requests\";\n\n/**\n * Metric unit from taxonomy\n * Aligned with config/crucible-ts/taxonomy/metrics.yaml#/$defs/metricUnit\n * Updated for Crucible v0.2.7 (adds 's' for seconds)\n */\nexport type MetricUnit = \"count\" | \"ms\" | \"bytes\" | \"percent\" | \"s\";\n\n/**\n * Histogram bucket for OTLP-compatible histograms\n */\nexport interface HistogramBucket {\n /** Upper bound (less-than-or-equal) for the bucket */\n le: number;\n /** Cumulative count up to and including this bucket */\n count: number;\n}\n\n/**\n * Histogram summary payload\n */\nexport interface HistogramSummary {\n /** Total count of observations */\n count: number;\n /** Sum of all observed values */\n sum: number;\n /** Ordered buckets with cumulative counts (OTLP-compatible) */\n buckets: HistogramBucket[];\n}\n\n/**\n * Metric value (scalar or histogram)\n */\nexport type MetricValue = number | HistogramSummary;\n\n/**\n * Metrics event structure\n * Aligned with schemas/crucible-ts/observability/metrics/v1.0.0/metrics-event.schema.json\n */\nexport interface MetricsEvent {\n /** RFC3339 timestamp of metric emission */\n timestamp: string;\n /** Metric identifier from taxonomy */\n name: MetricName;\n /** Measurement payload (scalar or histogram summary) */\n value: MetricValue;\n /** Optional key/value dimensions */\n tags?: Record<string, string>;\n /** Optional metric unit (defaults to taxonomy default) */\n unit?: MetricUnit;\n}\n\n/**\n * Histogram options for customization\n */\nexport interface HistogramOptions {\n /** Custom bucket boundaries (overrides default ADR-0007 buckets) */\n buckets?: number[];\n}\n\n/**\n * Flush options for metrics registry\n */\nexport interface FlushOptions {\n /** Optional logger function to emit metrics */\n emit?: (events: MetricsEvent[]) => void;\n}\n\n/**\n * Type guard to check if value is a histogram summary\n */\nexport function isHistogramSummary(value: unknown): value is HistogramSummary {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"count\" in value &&\n \"sum\" in value &&\n \"buckets\" in value\n );\n}\n\n/**\n * Type guard to check if metric name is valid\n * Aligned with Crucible v0.2.18 taxonomy\n */\nexport function isValidMetricName(name: string): name is MetricName {\n const validNames: MetricName[] = [\n // Core module metrics\n \"schema_validations\",\n \"schema_validation_errors\",\n \"config_load_ms\",\n \"config_load_errors\",\n \"pathfinder_find_ms\",\n \"pathfinder_validation_errors\",\n \"pathfinder_security_warnings\",\n \"foundry_lookup_count\",\n \"logging_emit_count\",\n \"logging_emit_latency_ms\",\n \"goneat_command_duration_ms\",\n // Prometheus exporter metrics\n \"prometheus_exporter_refresh_duration_seconds\",\n \"prometheus_exporter_refresh_total\",\n \"prometheus_exporter_refresh_errors_total\",\n \"prometheus_exporter_refresh_inflight\",\n \"prometheus_exporter_http_requests_total\",\n \"prometheus_exporter_http_errors_total\",\n \"prometheus_exporter_restarts_total\",\n // Foundry MIME detection metrics\n \"foundry_mime_detections_total_json\",\n \"foundry_mime_detections_total_xml\",\n \"foundry_mime_detections_total_yaml\",\n \"foundry_mime_detections_total_csv\",\n \"foundry_mime_detections_total_plain_text\",\n \"foundry_mime_detections_total_unknown\",\n \"foundry_mime_detection_ms_json\",\n \"foundry_mime_detection_ms_xml\",\n \"foundry_mime_detection_ms_yaml\",\n \"foundry_mime_detection_ms_csv\",\n \"foundry_mime_detection_ms_plain_text\",\n \"foundry_mime_detection_ms_unknown\",\n // Error handling metrics\n \"error_handling_wraps_total\",\n \"error_handling_wrap_ms\",\n // FulHash metrics\n \"fulhash_operations_total_xxh3_128\",\n \"fulhash_operations_total_sha256\",\n \"fulhash_hash_string_total\",\n \"fulhash_bytes_hashed_total\",\n \"fulhash_operation_ms\",\n // HTTP server metrics\n \"http_requests_total\",\n \"http_request_duration_seconds\",\n \"http_request_size_bytes\",\n \"http_response_size_bytes\",\n \"http_active_requests\",\n ];\n return validNames.includes(name as MetricName);\n}\n\n/**\n * Type guard to check if unit is valid\n */\nexport function isValidMetricUnit(unit: string): unit is MetricUnit {\n const validUnits: MetricUnit[] = [\"count\", \"ms\", \"bytes\", \"percent\", \"s\"];\n return validUnits.includes(unit as MetricUnit);\n}\n","/**\n * Metrics event validators\n *\n * Schema validation for metrics events using existing src/schema infrastructure\n */\n\nimport { compileSchemaById } from \"../schema/index.js\";\nimport type { CompiledValidator } from \"../schema/types.js\";\n\n/**\n * Singleton validator for metrics events\n *\n * Pre-compiles the metrics-event schema at first access for optimal performance.\n * Reuses existing AJV setup from src/schema module.\n */\nclass MetricsValidator {\n private static instance: MetricsValidator;\n private validateFn: CompiledValidator | null = null;\n private initPromise: Promise<void> | null = null;\n private initError: Error | null = null;\n\n private constructor() {\n // Private constructor for singleton\n }\n\n /**\n * Get singleton instance\n */\n static getInstance(): MetricsValidator {\n if (!MetricsValidator.instance) {\n MetricsValidator.instance = new MetricsValidator();\n }\n return MetricsValidator.instance;\n }\n\n /**\n * Initialize validator (lazy load, async)\n */\n private async init(): Promise<void> {\n if (this.validateFn !== null || this.initError !== null) {\n return; // Already initialized\n }\n\n if (this.initPromise) {\n return this.initPromise; // Already initializing\n }\n\n this.initPromise = (async () => {\n try {\n // Compile schema using existing schema infrastructure\n this.validateFn = await compileSchemaById(\"observability/metrics/v1.0.0/metrics-event\");\n } catch (err) {\n this.initError = err instanceof Error ? err : new Error(String(err));\n throw new Error(`Failed to initialize metrics validator: ${this.initError.message}`);\n }\n })();\n\n return this.initPromise;\n }\n\n /**\n * Validate metrics event against schema\n *\n * @param event - Metrics event to validate\n * @returns Promise resolving to true if valid, false otherwise\n */\n async validate(event: unknown): Promise<boolean> {\n if (this.validateFn === null) {\n await this.init();\n }\n\n if (this.initError) {\n throw this.initError;\n }\n\n if (!this.validateFn) {\n throw new Error(\"Validator not initialized\");\n }\n\n return this.validateFn(event);\n }\n\n /**\n * Get validation errors from last validation\n */\n getErrors() {\n if (!this.validateFn) {\n return null;\n }\n return this.validateFn.errors;\n }\n\n /**\n * Reset validator state (for testing)\n * @internal\n */\n static _reset(): void {\n MetricsValidator.instance = new MetricsValidator();\n }\n}\n\n/**\n * Validate metrics event against schema\n *\n * Uses pre-compiled validator singleton for optimal performance.\n *\n * @param event - Metrics event to validate\n * @returns Promise resolving to true if valid\n *\n * @example\n * ```typescript\n * const event: MetricsEvent = {\n * timestamp: new Date().toISOString(),\n * name: 'schema_validations',\n * value: 42\n * };\n *\n * if (await validateMetricsEvent(event)) {\n * // Event is schema-compliant\n * } else {\n * const errors = getValidationErrors();\n * console.error('Validation failed:', errors);\n * }\n * ```\n */\nexport async function validateMetricsEvent(event: unknown): Promise<boolean> {\n return MetricsValidator.getInstance().validate(event);\n}\n\n/**\n * Validate array of metrics events\n *\n * @param events - Array of metrics events\n * @returns Promise resolving to true if all valid\n */\nexport async function validateMetricsEvents(events: unknown[]): Promise<boolean> {\n for (const event of events) {\n if (!(await validateMetricsEvent(event))) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * Get validation errors from last validation\n */\nexport function getValidationErrors() {\n return MetricsValidator.getInstance().getErrors();\n}\n\n/**\n * Format validation errors as human-readable string\n */\nexport function formatValidationErrors(\n errors: Array<{ instancePath?: string; message?: string }>,\n): string {\n return errors\n .map((err) => {\n const path = err.instancePath || \"(root)\";\n const message = err.message || \"validation failed\";\n return `${path}: ${message}`;\n })\n .join(\"; \");\n}\n\n/**\n * Assert that metrics event is valid (throws if not)\n *\n * @param event - Metrics event to validate\n * @throws {Error} If validation fails\n */\nexport async function assertValidMetricsEvent(event: unknown): Promise<void> {\n if (!(await validateMetricsEvent(event))) {\n const errors = getValidationErrors();\n const message = errors ? formatValidationErrors(errors) : \"Metrics event validation failed\";\n throw new Error(`Invalid metrics event: ${message}`);\n }\n}\n\n// Export for testing\nexport { MetricsValidator };\n","/**\n * Telemetry module - metrics collection and export\n *\n * Provides counter, gauge, and histogram metrics with schema validation\n * and taxonomy-based defaults (ADR-0007).\n */\n\nexport const VERSION = \"1.0.0\";\n\n// Core registry and singleton\nexport { MetricsRegistry } from \"./registry.js\";\n\nimport { MetricsRegistry } from \"./registry.js\";\n\n/**\n * Default singleton metrics registry\n *\n * Use this for application-wide metrics collection.\n *\n * @example\n * ```typescript\n * import { metrics } from '@fulmenhq/tsfulmen/telemetry';\n *\n * // Increment counter\n * metrics.counter('schema_validations').inc();\n *\n * // Record histogram observation\n * metrics.histogram('config_load_ms').observe(42.5);\n *\n * // Export all metrics\n * const events = await metrics.export();\n * ```\n */\nexport const metrics = new MetricsRegistry();\n\n// Metric types\nexport { Counter } from \"./counter.js\";\nexport { Gauge } from \"./gauge.js\";\nexport { Histogram } from \"./histogram.js\";\n// Taxonomy\nexport type { MetricDefinition, MetricsTaxonomy } from \"./taxonomy.js\";\nexport {\n DEFAULT_MS_BUCKETS,\n getDefaultBuckets,\n getDefaultUnit,\n getMetric,\n getTaxonomy,\n isValidMetricName as isValidMetricNameTaxonomy,\n} from \"./taxonomy.js\";\n// Types\nexport type {\n FlushOptions,\n HistogramBucket,\n HistogramOptions,\n HistogramSummary,\n MetricName,\n MetricsEvent,\n MetricUnit,\n MetricValue,\n} from \"./types.js\";\nexport {\n isHistogramSummary,\n isValidMetricName,\n isValidMetricUnit,\n} from \"./types.js\";\n\n// Validators\nexport {\n assertValidMetricsEvent,\n formatValidationErrors,\n getValidationErrors,\n validateMetricsEvent,\n validateMetricsEvents,\n} from \"./validators.js\";\n","/**\n * Schema validator - implements AJV-based schema validation with goneat integration\n */\n\nimport { readFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { AnySchema } from \"ajv\";\nimport Ajv from \"ajv\";\nimport Ajv2019 from \"ajv/dist/2019.js\";\nimport Ajv2020 from \"ajv/dist/2020.js\";\nimport AjvDraft04 from \"ajv-draft-04\";\nimport { parse as parseYAML } from \"yaml\";\nimport { metrics } from \"../telemetry/index.js\";\nimport { applyFulmenAjvFormats } from \"./ajv-formats.js\";\nimport { SchemaValidationError } from \"./errors.js\";\nimport { getSchemaRegistry } from \"./registry.js\";\nimport type {\n CompiledValidator,\n SchemaInput,\n SchemaRegistryOptions,\n SchemaValidationResult,\n} from \"./types.js\";\nimport { createDiagnostic } from \"./utils.js\";\n\n/**\n * Supported JSON Schema dialects for meta validation + compilation.\n */\ntype JsonSchemaDialect = \"draft-04\" | \"draft-06\" | \"draft-07\" | \"draft-2019-09\" | \"draft-2020-12\";\n\n/**\n * AJV instances by dialect\n */\nconst ajvInstances = new Map<JsonSchemaDialect, Ajv>();\n\n/**\n * Metaschema initialization promises by dialect\n */\nconst metaschemaReady = new Map<JsonSchemaDialect, Promise<void>>();\n\n/**\n * Schema cache for compiled validators\n */\nconst schemaCache = new Map<string, CompiledValidator>();\n\n/**\n * Load metaschema from Crucible SSOT\n */\nasync function loadMetaSchema(draft: JsonSchemaDialect): Promise<Record<string, unknown>> {\n const __filename = fileURLToPath(import.meta.url);\n const __dirname = dirname(__filename);\n const metaSchemaPath = join(\n __dirname,\n \"..\",\n \"..\",\n \"schemas\",\n \"crucible-ts\",\n \"meta\",\n draft,\n \"schema.json\",\n );\n\n const content = await readFile(metaSchemaPath, \"utf-8\");\n return JSON.parse(content) as Record<string, unknown>;\n}\n\n/**\n * Load vocabulary schemas (draft 2019-09 / 2020-12)\n */\nasync function loadVocabularySchemas(draft: JsonSchemaDialect): Promise<Record<string, unknown>[]> {\n if (draft !== \"draft-2019-09\" && draft !== \"draft-2020-12\") {\n return [];\n }\n\n const __filename = fileURLToPath(import.meta.url);\n const __dirname = dirname(__filename);\n const vocabDir = join(__dirname, \"..\", \"..\", \"schemas\", \"crucible-ts\", \"meta\", draft, \"meta\");\n\n const vocabFiles =\n draft === \"draft-2020-12\"\n ? [\n \"core.json\",\n \"applicator.json\",\n \"unevaluated.json\",\n \"validation.json\",\n \"meta-data.json\",\n \"format-annotation.json\",\n \"content.json\",\n ]\n : [\n \"core.json\",\n \"applicator.json\",\n \"validation.json\",\n \"meta-data.json\",\n \"format.json\",\n \"content.json\",\n ];\n\n const schemas: Record<string, unknown>[] = [];\n for (const file of vocabFiles) {\n try {\n const content = await readFile(join(vocabDir, file), \"utf-8\");\n schemas.push(JSON.parse(content) as Record<string, unknown>);\n } catch {\n // Vocabulary schema not found, skip\n }\n }\n\n return schemas;\n}\n\n/**\n * Load referenced schemas (including YAML files) for AJV\n *\n * Resolves relative paths from schemas/ and config/ directories.\n * Handles both relative paths and https://schemas.fulmenhq.dev URIs.\n *\n * Per Canonical URI Resolution Standard (v0.4.2+), crucible-hosted schemas use:\n * https://schemas.fulmenhq.dev/crucible/<topic>/<version>/<filename>\n *\n * We only embed crucible schemas locally. Other modules (goneat/, enact/, etc.)\n * are not embedded and cannot be resolved offline.\n */\nasync function loadReferencedSchema(uri: string): Promise<Record<string, unknown>> {\n const __filename = fileURLToPath(import.meta.url);\n const __dirname = dirname(__filename);\n const repoRoot = join(__dirname, \"..\", \"..\");\n\n let resolvedPath: string;\n\n // Handle https://schemas.fulmenhq.dev/ URIs - map to local files\n if (uri.startsWith(\"https://schemas.fulmenhq.dev/\")) {\n let relativePath = uri.replace(\"https://schemas.fulmenhq.dev/\", \"\");\n\n // Strip crucible/ module prefix if present (v0.4.2+ canonical URIs)\n // We only embed crucible schemas - other modules cannot be resolved locally\n if (relativePath.startsWith(\"crucible/\")) {\n relativePath = relativePath.slice(\"crucible/\".length);\n }\n\n // Check if it's a config taxonomy reference\n if (relativePath.startsWith(\"config/taxonomy/\")) {\n resolvedPath = join(\n repoRoot,\n \"config\",\n \"crucible-ts\",\n \"taxonomy\",\n relativePath.split(\"/\").pop() || \"\",\n );\n } else {\n // Schema reference - map to schemas/crucible-ts/\n resolvedPath = join(repoRoot, \"schemas\", \"crucible-ts\", relativePath);\n }\n }\n // Handle relative paths (e.g., \"../../../../config/taxonomy/metrics.yaml\")\n else if (uri.startsWith(\"../../\") || uri.startsWith(\"../\")) {\n // Resolve relative to schemas/crucible-ts/observability/metrics/v1.0.0/\n // (where metrics-event.schema.json is located)\n const schemaBase = join(\n repoRoot,\n \"schemas\",\n \"crucible-ts\",\n \"observability\",\n \"metrics\",\n \"v1.0.0\",\n );\n resolvedPath = join(schemaBase, uri);\n }\n // Handle file:// URIs\n else if (uri.startsWith(\"file://\")) {\n resolvedPath = fileURLToPath(uri);\n }\n // Unhandled URI scheme\n else {\n throw new Error(`Cannot load remote schema: ${uri}`);\n }\n\n // Read and parse the file\n const content = await readFile(resolvedPath, \"utf-8\");\n const ext = resolvedPath.split(\".\").pop()?.toLowerCase();\n\n if (ext === \"yaml\" || ext === \"yml\") {\n return parseYAML(content) as Record<string, unknown>;\n }\n return JSON.parse(content) as Record<string, unknown>;\n}\n\n/**\n * Resolve JSON Schema dialect from schema content.\n */\nfunction detectDialect(schema: unknown): JsonSchemaDialect {\n if (schema && typeof schema === \"object\" && !Array.isArray(schema)) {\n const maybeSchema = schema as Record<string, unknown>;\n const declared = (maybeSchema as { $schema?: unknown }).$schema;\n\n if (typeof declared === \"string\") {\n if (declared.includes(\"draft-04\")) return \"draft-04\";\n if (declared.includes(\"draft-06\")) return \"draft-06\";\n if (declared.includes(\"draft-07\")) return \"draft-07\";\n if (declared.includes(\"draft/2019-09\")) return \"draft-2019-09\";\n if (declared.includes(\"draft/2020-12\")) return \"draft-2020-12\";\n }\n }\n\n // Default to 2020-12 in Fulmen ecosystem.\n return \"draft-2020-12\";\n}\n\n/**\n * Create AJV instance for a specific dialect\n */\nfunction createAjv(dialect: JsonSchemaDialect): Ajv {\n const AjvCtor =\n dialect === \"draft-2020-12\"\n ? Ajv2020\n : dialect === \"draft-2019-09\"\n ? Ajv2019\n : dialect === \"draft-04\"\n ? (AjvDraft04 as unknown as typeof Ajv)\n : Ajv;\n\n const ajv = new AjvCtor({\n strict: false,\n allErrors: true,\n verbose: true,\n // Allow schemas with $id to be added without replacing existing ones\n addUsedSchema: false,\n // draft-04 uses \"id\"; later drafts use \"$id\"\n schemaId: dialect === \"draft-04\" ? \"id\" : \"$id\",\n // Enable async schema loading for YAML references\n loadSchema: loadReferencedSchema,\n });\n\n applyFulmenAjvFormats(ajv);\n\n return ajv;\n}\n\n/**\n * Get or create AJV instance for a dialect, ensuring metaschemas are loaded.\n */\nasync function getAjv(dialect: JsonSchemaDialect): Promise<Ajv> {\n const existing = ajvInstances.get(dialect);\n if (existing) {\n const ready = metaschemaReady.get(dialect);\n if (ready) await ready;\n return existing;\n }\n\n const ajv = createAjv(dialect);\n ajvInstances.set(dialect, ajv);\n\n const readyPromise = Promise.all([loadVocabularySchemas(dialect), loadMetaSchema(dialect)])\n .then(([vocabSchemas, metaSchema]) => {\n // Add vocabulary schemas first (referenced by meta schema)\n for (const vocabSchema of vocabSchemas) {\n try {\n ajv.addMetaSchema(vocabSchema);\n } catch {\n // Already added or incompatible with Ajv's built-ins\n }\n }\n\n try {\n ajv.addMetaSchema(metaSchema);\n } catch {\n // Already added or incompatible with Ajv's built-ins\n }\n })\n .catch((error) => {\n throw new Error(`Failed to load metaschemas (${dialect}): ${error}`);\n });\n\n metaschemaReady.set(dialect, readyPromise);\n await readyPromise;\n\n return ajv;\n}\n\n/**\n * Compile a schema for validation\n */\nexport async function compileSchema(\n schema: SchemaInput,\n options: { aliases?: string[] } = {},\n): Promise<CompiledValidator> {\n const baseKey = typeof schema === \"string\" ? schema : JSON.stringify(schema);\n\n let parsedSchema: unknown;\n if (typeof schema === \"string\") {\n try {\n parsedSchema = JSON.parse(schema);\n } catch {\n // Try YAML if JSON parsing fails\n parsedSchema = parseYAML(schema);\n }\n } else if (Buffer.isBuffer(schema)) {\n const content = schema.toString(\"utf-8\");\n try {\n parsedSchema = JSON.parse(content);\n } catch {\n parsedSchema = parseYAML(content);\n }\n } else {\n parsedSchema = schema;\n }\n\n const dialect = detectDialect(parsedSchema);\n const ajv = await getAjv(dialect);\n\n const cacheKey = `${dialect}:${baseKey}`;\n const cached = schemaCache.get(cacheKey);\n if (cached !== undefined) {\n return cached;\n }\n\n try {\n // Register schema aliases (e.g., alternate $id values) before compile to support relative refs\n if (options.aliases && options.aliases.length > 0) {\n for (const alias of options.aliases) {\n if (alias && ajv.getSchema(alias) === undefined) {\n try {\n if (typeof parsedSchema === \"object\" && parsedSchema !== null) {\n ajv.addSchema(parsedSchema as Record<string, unknown>, alias);\n }\n } catch {\n // Ignore if alias already registered or invalid\n }\n }\n }\n }\n\n const validator =\n typeof parsedSchema === \"boolean\"\n ? ajv.compile(parsedSchema)\n : await ajv.compileAsync(parsedSchema as Record<string, unknown>);\n\n // Cache the compiled validator\n schemaCache.set(cacheKey, validator as CompiledValidator);\n\n return validator as CompiledValidator;\n } catch (error) {\n throw SchemaValidationError.parseFailed(\n {\n type: \"string\",\n content: typeof schema === \"string\" ? schema : JSON.stringify(schema),\n },\n error as Error,\n );\n }\n}\n\n/**\n * Validate data against a compiled schema\n */\nexport function validateData(data: unknown, validator: CompiledValidator): SchemaValidationResult {\n const valid = validator(data);\n\n const result: SchemaValidationResult = {\n valid,\n diagnostics: [],\n source: \"ajv\",\n };\n\n if (!valid && validator.errors) {\n const errors = validator.errors;\n if (Array.isArray(errors)) {\n result.diagnostics = errors.map((error) =>\n createDiagnostic(\n error.instancePath || \"\",\n error.message || \"Validation failed\",\n error.keyword || \"unknown\",\n \"ERROR\",\n \"ajv\",\n ),\n );\n }\n metrics.counter(\"schema_validation_errors\").inc();\n } else {\n metrics.counter(\"schema_validations\").inc();\n }\n\n return result;\n}\n\n/**\n * Validate file against a schema\n */\nexport async function validateFile(\n filePath: string,\n validator: CompiledValidator,\n): Promise<SchemaValidationResult> {\n try {\n const content = await readFile(filePath, \"utf-8\");\n let data: unknown;\n\n try {\n data = JSON.parse(content);\n } catch {\n // Try YAML if JSON parsing fails\n data = parseYAML(content);\n }\n\n return validateData(data, validator);\n } catch (error) {\n if (error instanceof SchemaValidationError) {\n throw error;\n }\n throw SchemaValidationError.validationFailed(\n filePath,\n [\n createDiagnostic(\n \"\",\n `Failed to read or parse file: ${(error as Error).message}`,\n \"file-read\",\n \"ERROR\",\n \"ajv\",\n ),\n ],\n { type: \"file\", id: filePath },\n );\n }\n}\n\n/**\n * Validate a schema document itself\n */\nexport async function validateSchema(schema: SchemaInput): Promise<SchemaValidationResult> {\n try {\n // Parse schema so we can both meta-validate and compile with dialect-specific Ajv.\n let parsedSchema: unknown;\n if (typeof schema === \"string\") {\n try {\n parsedSchema = JSON.parse(schema);\n } catch {\n parsedSchema = parseYAML(schema);\n }\n } else if (Buffer.isBuffer(schema)) {\n const content = schema.toString(\"utf-8\");\n try {\n parsedSchema = JSON.parse(content);\n } catch {\n parsedSchema = parseYAML(content);\n }\n } else {\n parsedSchema = schema;\n }\n\n const dialect = detectDialect(parsedSchema);\n const ajv = await getAjv(dialect);\n\n // 1) Meta validation against declared dialect\n const metaValid = ajv.validateSchema(parsedSchema as AnySchema);\n if (!metaValid && ajv.errors) {\n const diagnostics = ajv.errors.map((error) =>\n createDiagnostic(\n error.instancePath || \"\",\n error.message || \"Schema meta-validation failed\",\n error.keyword || \"unknown\",\n \"ERROR\",\n \"ajv\",\n ),\n );\n\n return { valid: false, diagnostics, source: \"ajv\" };\n }\n\n // 2) Compilation check (refs resolvable, keywords supported)\n await compileSchema(parsedSchema as SchemaInput);\n\n return {\n valid: true,\n diagnostics: [],\n source: \"ajv\",\n };\n } catch (error) {\n if (error instanceof SchemaValidationError) {\n return {\n valid: false,\n diagnostics: error.diagnostics,\n source: \"ajv\",\n };\n }\n\n return {\n valid: false,\n diagnostics: [\n createDiagnostic(\n \"\",\n `Schema validation failed: ${(error as Error).message}`,\n \"schema-validation\",\n \"ERROR\",\n \"ajv\",\n ),\n ],\n source: \"ajv\",\n };\n }\n}\n\n/**\n * Clear schema cache\n */\nexport function clearCache(): void {\n schemaCache.clear();\n // Keep Ajv instances cached; they hold metaschemas. Tests can still clear schema cache.\n}\n\n/**\n * Get schema cache size\n */\nexport function getCacheSize(): number {\n return schemaCache.size;\n}\n\n/**\n * Load schema by ID from registry and compile\n */\nexport async function compileSchemaById(\n schemaId: string,\n registryOptions?: SchemaRegistryOptions,\n): Promise<CompiledValidator> {\n try {\n const registry = getSchemaRegistry(registryOptions);\n const metadata = await registry.getSchema(schemaId);\n\n const content = await readFile(metadata.path, \"utf-8\");\n const aliases: string[] = [];\n\n const normalizedRelativePath = metadata.relativePath.replace(/\\\\/g, \"/\");\n if (normalizedRelativePath) {\n // Per Canonical URI Resolution Standard (v0.4.2+), include crucible/ module prefix\n aliases.push(\n new URL(`crucible/${normalizedRelativePath}`, \"https://schemas.fulmenhq.dev/\").toString(),\n );\n }\n\n return compileSchema(content, { aliases });\n } catch (error) {\n metrics.counter(\"schema_validation_errors\").inc();\n throw error;\n }\n}\n\n/**\n * Validate data against a schema ID from registry\n */\nexport async function validateDataBySchemaId(\n data: unknown,\n schemaId: string,\n registryOptions?: SchemaRegistryOptions,\n): Promise<SchemaValidationResult> {\n try {\n const validator = await compileSchemaById(schemaId, registryOptions);\n return validateData(data, validator);\n } catch (error) {\n metrics.counter(\"schema_validation_errors\").inc();\n throw error;\n }\n}\n\n/**\n * Validate file against a schema ID from registry\n */\nexport async function validateFileBySchemaId(\n filePath: string,\n schemaId: string,\n registryOptions?: SchemaRegistryOptions,\n): Promise<SchemaValidationResult> {\n try {\n const validator = await compileSchemaById(schemaId, registryOptions);\n return validateFile(filePath, validator);\n } catch (error) {\n metrics.counter(\"schema_validation_errors\").inc();\n throw error;\n }\n}\n","/**\n * Schema CLI - Commander-based CLI for schema operations\n *\n * Provides command-line interface for schema discovery, validation,\n * and normalization operations. This is a developer tool for exploration\n * and testing, not for production use.\n */\n\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport { Command } from \"commander\";\nimport { isGoneatAvailable, runGoneatValidation } from \"./goneat-bridge.js\";\nimport { compareSchemas, normalizeSchema } from \"./normalizer.js\";\nimport { getSchemaRegistry, listSchemas } from \"./registry.js\";\nimport type { CLIOptions, SchemaValidationResult } from \"./types.js\";\nimport { formatDiagnostics } from \"./utils.js\";\nimport { validateFileBySchemaId } from \"./validator.js\";\n\n/**\n * Create CLI command structure\n */\nexport function createCLI(options: CLIOptions = {}): Command {\n const program = new Command();\n\n program\n .name(\"tsfulmen-schema\")\n .description(\"Schema validation and discovery CLI for Fulmen (developer tool)\")\n .version(\"0.1.0\");\n\n // List schemas command\n program\n .command(\"list\")\n .description(\"List available schemas from registry\")\n .argument(\"[prefix]\", \"Filter schemas by prefix\")\n .option(\"--base-dir <path>\", \"Override schema base directory\")\n .action(async (prefix?: string, cmdOptions?: { baseDir?: string }) => {\n try {\n const schemas = await listSchemas(prefix, {\n baseDir: cmdOptions?.baseDir || options.baseDir,\n });\n\n if (schemas.length === 0) {\n console.log(\"No schemas found\");\n return;\n }\n\n console.log(`Found ${schemas.length} schema(s):\\n`);\n for (const schema of schemas) {\n console.log(` ${schema.id}`);\n console.log(` Format: ${schema.format}`);\n console.log(` Path: ${schema.relativePath}`);\n if (schema.description) {\n console.log(` Description: ${schema.description}`);\n }\n console.log();\n }\n } catch (error) {\n console.error(\"Error listing schemas:\", (error as Error).message);\n process.exit(1);\n }\n });\n\n // Show schema command\n program\n .command(\"show\")\n .description(\"Show schema details\")\n .requiredOption(\"--schema-id <id>\", \"Schema ID to show\")\n .option(\"--base-dir <path>\", \"Override schema base directory\")\n .action(async (cmdOptions: { schemaId: string; baseDir?: string }) => {\n try {\n const registry = getSchemaRegistry({\n baseDir: cmdOptions.baseDir || options.baseDir,\n });\n const schema = await registry.getSchema(cmdOptions.schemaId);\n\n console.log(\"Schema Details:\\n\");\n console.log(` ID: ${schema.id}`);\n console.log(` Format: ${schema.format}`);\n console.log(` Path: ${schema.path}`);\n console.log(` Relative Path: ${schema.relativePath}`);\n if (schema.version) {\n console.log(` Version: ${schema.version}`);\n }\n if (schema.description) {\n console.log(` Description: ${schema.description}`);\n }\n if (schema.schemaDraft) {\n console.log(` Schema Draft: ${schema.schemaDraft}`);\n }\n\n // Read and display schema content\n const content = await readFile(schema.path, \"utf-8\");\n console.log(\"\\nSchema Content:\");\n console.log(content);\n } catch (error) {\n console.error(\"Error showing schema:\", (error as Error).message);\n process.exit(1);\n }\n });\n\n // Validate data command\n program\n .command(\"validate\")\n .description(\"Validate data file against schema\")\n .requiredOption(\"--schema-id <id>\", \"Schema ID to validate against\")\n .argument(\"<file>\", \"Data file to validate\")\n .option(\"--use-goneat\", \"Use goneat for validation (requires goneat binary)\")\n .option(\"--goneat-path <path>\", \"Path to goneat binary\")\n .option(\"--base-dir <path>\", \"Override schema base directory\")\n .action(\n async (\n file: string,\n cmdOptions: {\n schemaId: string;\n useGoneat?: boolean;\n goneatPath?: string;\n baseDir?: string;\n },\n ) => {\n try {\n let result: SchemaValidationResult;\n\n if (cmdOptions.useGoneat) {\n // Check goneat availability\n const available = await isGoneatAvailable(cmdOptions.goneatPath);\n if (!available) {\n console.error(\"❌ goneat not available. Install goneat or remove --use-goneat flag.\");\n console.error(\" AJV validation (default) works without external dependencies.\");\n process.exit(1);\n }\n\n // Get schema path\n const registry = getSchemaRegistry({\n baseDir: cmdOptions.baseDir || options.baseDir,\n });\n const schema = await registry.getSchema(cmdOptions.schemaId);\n\n console.log(\"Using goneat validation...\");\n result = await runGoneatValidation(schema.path, file, cmdOptions.goneatPath);\n } else {\n // Use AJV validation (default, library implementation)\n console.log(\"Using AJV validation...\");\n result = await validateFileBySchemaId(file, cmdOptions.schemaId, {\n baseDir: cmdOptions.baseDir || options.baseDir,\n });\n }\n\n if (result.valid) {\n console.log(`✅ Validation passed (${result.source})`);\n process.exit(0);\n } else {\n console.log(`❌ Validation failed (${result.source})`);\n console.log(\"\\nDiagnostics:\");\n console.log(formatDiagnostics(result.diagnostics));\n process.exit(1);\n }\n } catch (error) {\n console.error(\"Error validating file:\", (error as Error).message);\n process.exit(1);\n }\n },\n );\n\n // Validate schema command\n program\n .command(\"validate-schema\")\n .description(\"Validate a schema file itself\")\n .argument(\"<file>\", \"Schema file to validate\")\n .action(async (file: string) => {\n try {\n const content = await readFile(file, \"utf-8\");\n const { validateSchema } = await import(\"./validator.js\");\n const result = await validateSchema(content);\n\n if (result.valid) {\n console.log(\"✅ Schema is valid\");\n process.exit(0);\n } else {\n console.log(\"❌ Schema is invalid\");\n console.log(\"\\nDiagnostics:\");\n console.log(formatDiagnostics(result.diagnostics));\n process.exit(1);\n }\n } catch (error) {\n console.error(\"Error validating schema:\", (error as Error).message);\n process.exit(1);\n }\n });\n\n // Normalize schema command\n program\n .command(\"normalize\")\n .description(\"Normalize schema to canonical JSON format\")\n .argument(\"<file>\", \"Schema file to normalize\")\n .option(\"--compact\", \"Output compact JSON (no formatting)\")\n .option(\"-o, --output <file>\", \"Write to output file instead of stdout\")\n .action(async (file: string, cmdOptions: { compact?: boolean; output?: string }) => {\n try {\n const content = await readFile(file, \"utf-8\");\n const normalized = normalizeSchema(content, {\n compact: cmdOptions.compact,\n });\n\n if (cmdOptions.output) {\n await writeFile(cmdOptions.output, normalized, \"utf-8\");\n console.log(`✅ Normalized schema written to ${cmdOptions.output}`);\n } else {\n console.log(normalized);\n }\n } catch (error) {\n console.error(\"Error normalizing schema:\", (error as Error).message);\n process.exit(1);\n }\n });\n\n // Compare schemas command\n program\n .command(\"compare\")\n .description(\"Compare two schemas for semantic equality\")\n .argument(\"<file1>\", \"First schema file\")\n .argument(\"<file2>\", \"Second schema file\")\n .option(\"--show-normalized\", \"Show normalized outputs\")\n .action(async (file1: string, file2: string, cmdOptions: { showNormalized?: boolean }) => {\n try {\n const content1 = await readFile(file1, \"utf-8\");\n const content2 = await readFile(file2, \"utf-8\");\n\n const result = compareSchemas(content1, content2);\n\n if (result.equal) {\n console.log(\"✅ Schemas are semantically equal\");\n } else {\n console.log(\"❌ Schemas differ\");\n }\n\n if (cmdOptions.showNormalized) {\n console.log(\"\\nNormalized Schema 1:\");\n console.log(result.normalizedA);\n console.log(\"\\nNormalized Schema 2:\");\n console.log(result.normalizedB);\n }\n\n process.exit(result.equal ? 0 : 1);\n } catch (error) {\n console.error(\"Error comparing schemas:\", (error as Error).message);\n process.exit(1);\n }\n });\n\n // Export schema command\n program\n .command(\"export\")\n .description(\"Export schema from registry to file with provenance\")\n .requiredOption(\"--schema-id <id>\", \"Schema ID to export\")\n .requiredOption(\"--out <path>\", \"Output file path\")\n .option(\"--force\", \"Overwrite existing file\", false)\n .option(\"--no-provenance\", \"Exclude provenance metadata\")\n .option(\"--no-validate\", \"Skip schema validation before export\")\n .option(\"--format <format>\", \"Export format (json|yaml|auto)\", \"auto\")\n .option(\"--base-dir <path>\", \"Override schema base directory\")\n .action(\n async (cmdOptions: {\n schemaId: string;\n out: string;\n force?: boolean;\n provenance?: boolean;\n validate?: boolean;\n format?: string;\n baseDir?: string;\n }) => {\n try {\n const { exportSchema } = await import(\"./export.js\");\n const { exitCodes } = await import(\"../foundry/index.js\");\n\n const result = await exportSchema({\n schemaId: cmdOptions.schemaId,\n outPath: cmdOptions.out,\n includeProvenance: cmdOptions.provenance ?? true,\n validate: cmdOptions.validate ?? true,\n overwrite: cmdOptions.force ?? false,\n format: (cmdOptions.format as \"json\" | \"yaml\" | \"auto\") ?? \"auto\",\n baseDir: cmdOptions.baseDir || options.baseDir,\n });\n\n console.log(\"✅ Schema exported successfully\");\n console.log(` Schema ID: ${result.schemaId}`);\n console.log(` Output: ${result.outPath}`);\n console.log(` Format: ${result.format}`);\n\n if (result.provenance) {\n console.log(\"\\nProvenance:\");\n console.log(` Crucible: ${result.provenance.crucible_version}`);\n console.log(` Library: ${result.provenance.library_version}`);\n if (result.provenance.revision) {\n console.log(` Revision: ${result.provenance.revision}`);\n }\n console.log(` Exported: ${result.provenance.exported_at}`);\n }\n\n process.exit(exitCodes.EXIT_SUCCESS);\n } catch (error) {\n const { exitCodes } = await import(\"../foundry/index.js\");\n const { SchemaExportError, SchemaValidationError, ExportErrorReason } = await import(\n \"./errors.js\"\n );\n\n console.error(\"❌ Schema export failed:\", (error as Error).message);\n\n // Map specific error types to appropriate exit codes\n if (error instanceof SchemaExportError) {\n if (error.outPath) {\n console.error(` Output path: ${error.outPath}`);\n }\n\n // Use error reason for type-safe exit code mapping\n switch (error.reason) {\n case ExportErrorReason.FILE_EXISTS:\n case ExportErrorReason.WRITE_FAILED:\n process.exit(exitCodes.EXIT_FILE_WRITE_ERROR);\n break;\n\n case ExportErrorReason.INVALID_FORMAT:\n process.exit(exitCodes.EXIT_INVALID_ARGUMENT);\n break;\n\n default:\n // PROVENANCE_FAILED, UNKNOWN, and any future reasons\n process.exit(exitCodes.EXIT_FAILURE);\n }\n }\n\n if (error instanceof SchemaValidationError) {\n // Schema not found or validation failed\n const errorMsg = error.message.toLowerCase();\n\n if (errorMsg.includes(\"not found\")) {\n process.exit(exitCodes.EXIT_FILE_NOT_FOUND);\n }\n\n // Validation failures\n process.exit(exitCodes.EXIT_DATA_INVALID);\n }\n\n process.exit(exitCodes.EXIT_FAILURE);\n }\n },\n );\n\n // Identity show command\n program\n .command(\"identity-show\")\n .description(\"Show application identity from .fulmen/app.yaml\")\n .option(\"--path <path>\", \"Explicit path to app.yaml\")\n .option(\"--json\", \"Output as JSON\")\n .action(async (cmdOptions: { path?: string; json?: boolean }) => {\n try {\n const { loadIdentity } = await import(\"../appidentity/loader.js\");\n const { exitCodes } = await import(\"../foundry/index.js\");\n\n const identity = await loadIdentity({ path: cmdOptions.path });\n\n if (cmdOptions.json) {\n console.log(JSON.stringify(identity, null, 2));\n } else {\n console.log(\"Application Identity:\\n\");\n console.log(` Binary Name: ${identity.app.binary_name}`);\n console.log(` Vendor: ${identity.app.vendor}`);\n console.log(` Env Prefix: ${identity.app.env_prefix}`);\n console.log(` Config Name: ${identity.app.config_name}`);\n console.log(` Description: ${identity.app.description}`);\n\n if (identity.metadata) {\n console.log(\"\\nMetadata:\");\n if (identity.metadata.license) {\n console.log(` License: ${identity.metadata.license}`);\n }\n if (identity.metadata.repository_category) {\n console.log(` Category: ${identity.metadata.repository_category}`);\n }\n if (identity.metadata.telemetry_namespace) {\n console.log(` Telemetry: ${identity.metadata.telemetry_namespace}`);\n }\n if (identity.metadata.project_url) {\n console.log(` Project URL: ${identity.metadata.project_url}`);\n }\n }\n }\n\n process.exit(exitCodes.EXIT_SUCCESS);\n } catch (error) {\n const { exitCodes } = await import(\"../foundry/index.js\");\n const { AppIdentityError } = await import(\"../appidentity/errors.js\");\n\n console.error(\"❌ Failed to load identity:\", (error as Error).message);\n\n if (error instanceof AppIdentityError) {\n if (error.message.includes(\"not found\")) {\n process.exit(exitCodes.EXIT_FILE_NOT_FOUND);\n }\n if (error.message.includes(\"Invalid\") || error.message.includes(\"validation\")) {\n process.exit(exitCodes.EXIT_DATA_INVALID);\n }\n }\n\n process.exit(exitCodes.EXIT_FAILURE);\n }\n });\n\n // Identity validate command\n program\n .command(\"identity-validate\")\n .description(\"Validate application identity against schema\")\n .argument(\"[file]\", \"Path to app.yaml (defaults to discovery)\")\n .action(async (file?: string) => {\n try {\n const { loadIdentity } = await import(\"../appidentity/loader.js\");\n const { exitCodes } = await import(\"../foundry/index.js\");\n\n console.log(\"Validating application identity...\");\n\n const identity = await loadIdentity({ path: file });\n\n console.log(\"✅ Identity is valid\");\n console.log(` Binary: ${identity.app.binary_name}`);\n console.log(` Vendor: ${identity.app.vendor}`);\n\n process.exit(exitCodes.EXIT_SUCCESS);\n } catch (error) {\n const { exitCodes } = await import(\"../foundry/index.js\");\n const { AppIdentityError } = await import(\"../appidentity/errors.js\");\n\n console.error(\"❌ Identity validation failed:\", (error as Error).message);\n\n if (error instanceof AppIdentityError) {\n if (error.message.includes(\"not found\")) {\n process.exit(exitCodes.EXIT_FILE_NOT_FOUND);\n }\n if (error.message.includes(\"Invalid\") || error.message.includes(\"validation\")) {\n process.exit(exitCodes.EXIT_DATA_INVALID);\n }\n }\n\n process.exit(exitCodes.EXIT_FAILURE);\n }\n });\n\n return program;\n}\n","/**\n * Schema export utilities - implements schema export with provenance\n */\n\nimport { access, mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname, extname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { parse as parseYAML, stringify as stringifyYAML } from \"yaml\";\nimport { SchemaExportError, SchemaValidationError } from \"./errors.js\";\nimport { getSchemaRegistry } from \"./registry.js\";\nimport type {\n ExportSchemaOptions,\n ExportSchemaResult,\n SchemaExportFormat,\n SchemaProvenanceMetadata,\n} from \"./types.js\";\nimport { validateSchema } from \"./validator.js\";\n\n/**\n * Extract provenance metadata from Crucible sync metadata\n */\nasync function extractProvenanceMetadata(schemaId: string): Promise<SchemaProvenanceMetadata> {\n try {\n // Read Crucible metadata using proper path resolution\n const __filename = fileURLToPath(import.meta.url);\n const __dirname = dirname(__filename);\n const metadataPath = join(__dirname, \"..\", \"..\", \".crucible\", \"metadata\", \"metadata.yaml\");\n const metadataContent = await readFile(metadataPath, \"utf-8\");\n\n // Parse YAML properly to avoid brittle regex matching\n const metadata = parseYAML(metadataContent) as {\n sources?: Array<{\n name?: string;\n version?: string;\n commit?: string;\n }>;\n };\n\n // Extract Crucible source metadata (first source is typically 'crucible')\n const crucibleSource = metadata.sources?.[0];\n const crucibleVersion = crucibleSource?.version || \"unknown\";\n const revision = crucibleSource?.commit;\n\n // Read library version from package.json\n const pkgPath = join(__dirname, \"..\", \"..\", \"package.json\");\n const pkgContent = await readFile(pkgPath, \"utf-8\");\n const pkg = JSON.parse(pkgContent) as { version: string };\n\n return {\n schema_id: schemaId,\n crucible_version: crucibleVersion,\n library_version: pkg.version,\n revision: revision,\n exported_at: new Date().toISOString(),\n export_source: \"tsfulmen\",\n };\n } catch (error) {\n throw SchemaExportError.provenanceFailed((error as Error).message, error as Error);\n }\n}\n\n/**\n * Embed provenance metadata in schema content\n */\nfunction embedProvenance(\n schemaContent: Record<string, unknown>,\n provenance: SchemaProvenanceMetadata,\n format: SchemaExportFormat,\n): string {\n if (format === \"json\") {\n // For JSON: embed under $comment[\"x-crucible-source\"]\n const withProvenance = {\n ...schemaContent,\n $comment: {\n ...(typeof schemaContent.$comment === \"object\" ? schemaContent.$comment : {}),\n \"x-crucible-source\": provenance,\n },\n };\n return JSON.stringify(withProvenance, null, 2);\n }\n\n // For YAML: prepend comment block\n const yamlContent = stringifyYAML(schemaContent, {\n indent: 2,\n lineWidth: 0,\n });\n\n const provenanceComment = [\n \"# x-crucible-source:\",\n `# schema_id: ${provenance.schema_id}`,\n `# crucible_version: ${provenance.crucible_version}`,\n `# library_version: ${provenance.library_version}`,\n ...(provenance.revision ? [`# revision: ${provenance.revision}`] : []),\n `# exported_at: ${provenance.exported_at}`,\n `# export_source: ${provenance.export_source}`,\n \"\",\n ].join(\"\\n\");\n\n return provenanceComment + yamlContent;\n}\n\n/**\n * Detect export format from file extension or explicit option\n */\nfunction detectFormat(outPath: string, formatOption?: SchemaExportFormat): SchemaExportFormat {\n if (formatOption && formatOption !== \"auto\") {\n return formatOption;\n }\n\n const ext = extname(outPath).toLowerCase();\n switch (ext) {\n case \".json\":\n return \"json\";\n case \".yaml\":\n case \".yml\":\n return \"yaml\";\n default:\n throw SchemaExportError.invalidFormat(ext, outPath);\n }\n}\n\n/**\n * Export schema from registry to file with provenance\n *\n * @param options - Export options\n * @returns Export result with metadata\n *\n * @throws {SchemaExportError} If export fails\n * @throws {SchemaValidationError} If schema not found or validation fails\n *\n * @example\n * ```typescript\n * import { exportSchema } from '@fulmenhq/tsfulmen/schema';\n *\n * await exportSchema({\n * schemaId: 'library/foundry/v1.0.0/exit-codes',\n * outPath: './schemas/exit-codes.schema.json',\n * includeProvenance: true,\n * validate: true,\n * });\n * ```\n */\nexport async function exportSchema(options: ExportSchemaOptions): Promise<ExportSchemaResult> {\n const {\n schemaId,\n outPath,\n includeProvenance = true,\n validate = true,\n overwrite = false,\n format: formatOption,\n baseDir,\n } = options;\n\n // Detect output format\n const format = detectFormat(outPath, formatOption);\n\n // Check if file exists\n if (!overwrite) {\n try {\n await access(outPath);\n throw SchemaExportError.fileExists(outPath);\n } catch (error) {\n // File doesn't exist - proceed\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") {\n throw error;\n }\n }\n }\n\n // Get schema from registry\n const registry = getSchemaRegistry({ baseDir });\n const schema = await registry.getSchema(schemaId);\n\n // Read schema content\n const schemaContent = await readFile(schema.path, \"utf-8\");\n\n // Validate if requested\n if (validate) {\n const validationResult = await validateSchema(schemaContent);\n if (!validationResult.valid) {\n throw SchemaValidationError.validationFailed(schemaId, validationResult.diagnostics, {\n type: \"file\",\n id: schema.path,\n });\n }\n }\n\n // Parse schema content\n let schemaObject: Record<string, unknown>;\n try {\n schemaObject = JSON.parse(schemaContent) as Record<string, unknown>;\n } catch {\n schemaObject = parseYAML(schemaContent) as Record<string, unknown>;\n }\n\n // Freeze schema object to prevent mutation\n Object.freeze(schemaObject);\n\n let provenance: SchemaProvenanceMetadata | undefined;\n let outputContent: string;\n\n if (includeProvenance) {\n // Extract provenance metadata\n provenance = await extractProvenanceMetadata(schemaId);\n\n // Embed provenance in output\n outputContent = embedProvenance(schemaObject, provenance, format);\n } else {\n // Export without provenance\n if (format === \"json\") {\n outputContent = JSON.stringify(schemaObject, null, 2);\n } else {\n outputContent = stringifyYAML(schemaObject, { indent: 2, lineWidth: 0 });\n }\n }\n\n // Ensure output directory exists\n await mkdir(dirname(outPath), { recursive: true });\n\n // Write to file\n try {\n await writeFile(outPath, outputContent, \"utf-8\");\n } catch (error) {\n throw SchemaExportError.writeFailed(outPath, error as Error);\n }\n\n return {\n success: true,\n schemaId,\n outPath,\n format,\n includeProvenance,\n provenance,\n };\n}\n\n/**\n * Strip provenance metadata from schema content\n *\n * This helper is useful for comparing exported schemas with runtime\n * schemas or validating that provenance doesn't affect schema semantics.\n *\n * @param content - Schema content (JSON or YAML string)\n * @returns Schema content without provenance metadata\n *\n * @example\n * ```typescript\n * import { stripProvenance } from '@fulmenhq/tsfulmen/schema';\n *\n * const exported = await readFile('./schema.json', 'utf-8');\n * const withoutProvenance = stripProvenance(exported);\n * ```\n */\nexport function stripProvenance(content: string): string {\n try {\n // Try parsing as JSON\n const parsed = JSON.parse(content) as Record<string, unknown>;\n\n // Remove provenance from $comment\n if (parsed.$comment && typeof parsed.$comment === \"object\") {\n const comment = { ...parsed.$comment } as Record<string, unknown>;\n delete comment[\"x-crucible-source\"];\n\n // Remove $comment entirely if it's now empty\n if (Object.keys(comment).length === 0) {\n delete parsed.$comment;\n } else {\n parsed.$comment = comment;\n }\n }\n\n return JSON.stringify(parsed, null, 2);\n } catch {\n // YAML format - strip comment lines\n const lines = content.split(\"\\n\");\n const filtered = lines.filter((line) => {\n const trimmed = line.trim();\n return !(\n trimmed.startsWith(\"# x-crucible-source:\") ||\n (trimmed.startsWith(\"# \") &&\n /^#\\s+(schema_id|crucible_version|library_version|revision|exported_at|export_source):/.test(\n trimmed,\n ))\n );\n });\n\n // Remove leading blank lines\n while (filtered.length > 0 && filtered[0]?.trim() === \"\") {\n filtered.shift();\n }\n\n return filtered.join(\"\\n\");\n }\n}\n","/**\n * Schema validation module - implements Fulmen Schema Validation Standard\n *\n * Provides schema discovery, validation, and normalization utilities for Crucible schemas\n * with JSON Schema 2020-12 support and optional goneat integration.\n */\n\nexport const VERSION = \"0.1.0\";\n\nexport {\n applyFulmenAjvFormats,\n type FulmenAjvFormatsOptions,\n} from \"./ajv-formats.js\";\n\n// CLI exports\nexport { createCLI } from \"./cli.js\";\n// Error exports\nexport * from \"./errors.js\";\n// Export exports\nexport { exportSchema, stripProvenance } from \"./export.js\";\n// Goneat bridge exports (CLI-only, optional)\nexport {\n detectGoneat,\n isGoneatAvailable,\n runGoneatValidation,\n} from \"./goneat-bridge.js\";\n// Normalizer exports\nexport { compareSchemas, normalizeSchema } from \"./normalizer.js\";\n// Registry exports\nexport {\n getSchema,\n getSchemaByPath,\n getSchemaRegistry,\n hasSchema,\n listSchemas,\n SchemaRegistry,\n} from \"./registry.js\";\n// Core exports\nexport type {\n AjvError,\n CLIOptions,\n CompiledValidator,\n ExportSchemaOptions,\n ExportSchemaResult,\n SchemaComparisonResult,\n SchemaExportFormat,\n SchemaFormat,\n SchemaInput,\n SchemaMetadata,\n SchemaNormalizationOptions,\n SchemaProvenanceMetadata,\n SchemaRegistryOptions,\n SchemaSource,\n SchemaValidationDiagnostic,\n SchemaValidationOptions,\n SchemaValidationResult,\n} from \"./types.js\";\n// Utility exports\nexport {\n countDiagnostics,\n createDiagnostic,\n formatDiagnostics,\n formatValidationResult,\n groupDiagnosticsBySeverity,\n isValidationError,\n normalizePointer,\n} from \"./utils.js\";\n// Validator exports\nexport {\n clearCache,\n compileSchema,\n compileSchemaById,\n getCacheSize,\n validateData,\n validateDataBySchemaId,\n validateFile,\n validateFileBySchemaId,\n validateSchema,\n} from \"./validator.js\";\n","/**\n * Environment variable alias utilities.\n *\n * Workhorse templates sometimes support both canonical nested env vars and\n * convenience aliases (e.g. TUVAN_SERVER_PORT vs TUVAN_PORT).\n *\n * This helper standardizes alias resolution and conflict reporting.\n */\n\nexport interface EnvAliasConflict {\n canonicalKey: string;\n aliasKey: string;\n canonicalValue: string;\n aliasValue: string;\n}\n\nexport interface ResolveEnvAliasesResult {\n env: Record<string, string | undefined>;\n applied: Array<{ aliasKey: string; canonicalKey: string }>;\n conflicts: EnvAliasConflict[];\n}\n\n/**\n * Resolve env var aliases into canonical keys.\n *\n * - If canonical key is unset and alias is set, the alias value is copied to canonical.\n * - If both are set and differ, a conflict is recorded (canonical is left unchanged).\n */\nexport function resolveEnvAliases(\n env: Record<string, string | undefined>,\n aliasToCanonical: Record<string, string>,\n): ResolveEnvAliasesResult {\n const out: Record<string, string | undefined> = { ...env };\n const applied: Array<{ aliasKey: string; canonicalKey: string }> = [];\n const conflicts: EnvAliasConflict[] = [];\n\n for (const [aliasKey, canonicalKey] of Object.entries(aliasToCanonical)) {\n const aliasValue = env[aliasKey];\n if (aliasValue === undefined || aliasValue === \"\") continue;\n\n const canonicalValue = env[canonicalKey];\n if (canonicalValue === undefined || canonicalValue === \"\") {\n out[canonicalKey] = aliasValue;\n applied.push({ aliasKey, canonicalKey });\n continue;\n }\n\n if (canonicalValue !== aliasValue) {\n conflicts.push({\n canonicalKey,\n aliasKey,\n canonicalValue,\n aliasValue,\n });\n }\n }\n\n return { env: out, applied, conflicts };\n}\n","/**\n * Config Path API errors - implements Fulmen Config Path Standard error handling\n */\n\n/**\n * Base error class for config path operations\n */\nexport class ConfigPathError extends Error {\n constructor(\n message: string,\n public cause?: Error,\n ) {\n super(message);\n this.name = \"ConfigPathError\";\n\n // Maintains proper stack trace for where our error was thrown (only available on V8)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, ConfigPathError);\n }\n }\n\n /**\n * Create error for invalid application identifier\n */\n static invalidAppIdentifier(identifier: unknown): ConfigPathError {\n return new ConfigPathError(\n `Invalid application identifier: ${JSON.stringify(identifier)}. Expected { vendor: string, app: string }`,\n );\n }\n\n /**\n * Create error for invalid vendor/app names\n */\n static invalidName(name: string, type: \"vendor\" | \"app\"): ConfigPathError {\n return new ConfigPathError(\n `Invalid ${type} name: \"${name}\". Must be lowercase kebab-case (e.g., 'fulmenhq', 'my-app')`,\n );\n }\n\n /**\n * Create error for home directory detection failure\n */\n static homeDirNotFound(): ConfigPathError {\n return new ConfigPathError(\n \"Unable to determine home directory. Please set HOME environment variable.\",\n );\n }\n\n /**\n * Create error for directory creation failure\n */\n static directoryCreationFailed(path: string, cause: Error): ConfigPathError {\n return new ConfigPathError(`Failed to create directory: ${path}`, cause);\n }\n\n /**\n * Create error for invalid environment variable\n */\n static invalidEnvVar(varName: string, value: string): ConfigPathError {\n return new ConfigPathError(\n `Invalid environment variable ${varName}: ${value}. Path must be absolute and within user home directory.`,\n );\n }\n}\n\n/**\n * Error thrown when configuration validation fails\n */\nexport class ConfigValidationError extends Error {\n constructor(\n message: string,\n public diagnostics?: unknown[],\n public cause?: Error,\n ) {\n super(message);\n this.name = \"ConfigValidationError\";\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, ConfigValidationError);\n }\n }\n}\n","import { readFile } from \"node:fs/promises\";\nimport { extname } from \"node:path\";\nimport { parse } from \"yaml\";\nimport { compileSchema, validateData } from \"../schema/index.js\";\nimport { ConfigValidationError } from \"./errors.js\";\nimport { getConfigSearchPaths, resolveConfigPath } from \"./paths.js\";\nimport type { AppIdentifier } from \"./types.js\";\n\n/**\n * Fields common to all `loadConfig` call shapes (independent of how the\n * defaults layer is supplied).\n */\nexport interface BaseLoadConfigOptions {\n /**\n * Application identifier for resolving user config paths\n */\n identity: AppIdentifier;\n\n /**\n * Optional absolute path to a schema file for validation.\n *\n * If both `schemaPath` and inline `schema` are given, `schema` takes precedence.\n */\n schemaPath?: string;\n\n /**\n * Inline schema content (JSON or YAML string) for validation.\n *\n * Provide this instead of `schemaPath` when the schema is embedded at build\n * time. Note: schema validation still requires the JSON-Schema metaschema,\n * which tsfulmen currently loads from disk — full in-binary config validation\n * lands with the asset-embedding work (Phase 2 / v0.4.0).\n */\n schema?: string;\n\n /**\n * Optional environment variable prefix for overrides\n * Defaults to identity.app.env_prefix if available, otherwise identity.app upper-cased\n */\n envPrefix?: string;\n\n /**\n * Optional override for the user config filename (excluding extension)\n * Defaults to identity.app.config_name or identity.app\n */\n userConfigName?: string;\n\n /**\n * Include env var consumption metadata for diagnostics.\n *\n * When enabled, loadConfig() records which environment variable keys were\n * consumed for prefix-based overrides.\n */\n includeEnvVarReport?: boolean;\n}\n\n/**\n * Options for loading configuration from a defaults **file path**.\n *\n * This is the original, patch-stable shape: `defaultsPath` is required and\n * typed `string`. For build-time embedded defaults (no file on disk), use\n * {@link LoadInlineConfigOptions} instead.\n */\nexport interface LoadConfigOptions extends BaseLoadConfigOptions {\n /**\n * Absolute path to the defaults configuration file. This file MUST exist.\n */\n defaultsPath: string;\n\n /** Mutually exclusive with {@link LoadInlineConfigOptions.defaults}. */\n defaults?: never;\n}\n\n/**\n * Options for loading configuration from **inline defaults** content.\n *\n * Provide a pre-parsed `defaults` object instead of a `defaultsPath` when the\n * defaults are embedded at build time (e.g. a `bun --compile` single-file\n * binary, where the defaults file is not on disk). Avoids the temp-file dance\n * of writing embedded content out just to pass a path.\n */\nexport interface LoadInlineConfigOptions extends BaseLoadConfigOptions {\n /**\n * Inline defaults content as a pre-parsed object.\n */\n defaults: Record<string, unknown>;\n\n /** Mutually exclusive with {@link LoadConfigOptions.defaultsPath}. */\n defaultsPath?: never;\n}\n\n/**\n * Metadata about the loaded configuration\n */\nexport interface ConfigMetadata {\n /**\n * Path to the defaults file used.\n *\n * Empty string (`\"\"`) when inline `defaults` was provided (there is no backing\n * file). Path-based callers always get the path they passed — the static type\n * stays `string` for patch compatibility. Use `defaultsSource` to distinguish\n * the inline case unambiguously.\n */\n defaultsPath: string;\n\n /**\n * Origin of the defaults layer: a file path (`\"path\"`) or inline `defaults`\n * content (`\"inline\"`). Optional/additive — present from the inline-defaults\n * feature onward.\n */\n defaultsSource?: \"path\" | \"inline\";\n\n /**\n * Path to the user config file used (null if not found)\n */\n userConfigPath: string | null;\n\n /**\n * Environment variable prefix used for overrides\n */\n envPrefix: string;\n\n /**\n * Environment variable keys consumed (only when includeEnvVarReport is enabled)\n */\n envVarsConsumed?: string[];\n\n /**\n * Count of environment variable keys consumed (only when includeEnvVarReport is enabled)\n */\n envVarsConsumedCount?: number;\n\n /**\n * List of active configuration layers (\"defaults\", \"user\", \"env\")\n */\n activeLayers: string[];\n\n /**\n * Schema validation information\n */\n schema: {\n /**\n * Path to the schema file used (null when none, or when inline `schema`\n * content was provided — inline has no backing file).\n */\n path: string | null;\n /**\n * Origin of the schema used for validation: a file path (`\"path\"`) or inline\n * `schema` content (`\"inline\"`), or `null` when no schema was provided.\n * Optional/additive.\n */\n source?: \"path\" | \"inline\" | null;\n /**\n * Whether validation was performed\n */\n validated: boolean;\n };\n}\n\n/**\n * Result of a configuration load operation\n */\nexport interface LoadedConfig<T> {\n /**\n * The merged configuration object\n */\n config: T;\n\n /**\n * Metadata about the loading process\n */\n metadata: ConfigMetadata;\n}\n\n/**\n * Deep merge two objects.\n * - Arrays are replaced, not merged.\n * - Objects are merged recursively.\n * - primitives are replaced.\n */\n// biome-ignore lint/suspicious/noExplicitAny: Deep merge util handles arbitrary config objects\nfunction deepMerge(target: any, source: any): any {\n if (typeof source !== \"object\" || source === null) {\n return source;\n }\n\n if (Array.isArray(source)) {\n return structuredClone(source);\n }\n\n if (typeof target !== \"object\" || target === null || Array.isArray(target)) {\n return structuredClone(source);\n }\n\n const output = { ...target };\n\n for (const key of Object.keys(source)) {\n if (Object.hasOwn(source, key)) {\n if (key in target) {\n output[key] = deepMerge(target[key], source[key]);\n } else {\n output[key] = structuredClone(source[key]);\n }\n }\n }\n\n return output;\n}\n\n/**\n * Parse a value from an environment variable string\n */\n// biome-ignore lint/suspicious/noExplicitAny: Return type depends on parsing result (string, number, bool, object)\nfunction parseEnvValue(value: string): any {\n // Boolean\n if (value.toLowerCase() === \"true\") return true;\n if (value.toLowerCase() === \"false\") return false;\n\n // Number\n if (!Number.isNaN(Number(value)) && value.trim() !== \"\") {\n return Number(value);\n }\n\n // JSON (e.g. array or object)\n try {\n const parsed = JSON.parse(value);\n if (typeof parsed === \"object\" || Array.isArray(parsed)) {\n return parsed;\n }\n } catch {\n // Ignore JSON parse errors, treat as string\n }\n\n return value;\n}\n\n/**\n * Parse environment variables into a config object\n */\n// biome-ignore lint/suspicious/noExplicitAny: Config object is dynamically constructed\nfunction parseEnvVars(prefix: string): any {\n // biome-ignore lint/suspicious/noExplicitAny: Config object is dynamically constructed\n const config: any = {};\n const prefixWithSeparator = `${prefix}_`;\n\n for (const [key, value] of Object.entries(process.env)) {\n if (!value) continue;\n\n if (key.startsWith(prefixWithSeparator)) {\n const keyWithoutPrefix = key.slice(prefixWithSeparator.length);\n const parts = keyWithoutPrefix.split(\"_\").filter((p) => p.length > 0);\n\n let current = config;\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i].toLowerCase();\n\n // If it's the last part, set the value\n if (i === parts.length - 1) {\n current[part] = parseEnvValue(value);\n } else {\n // Create nested object if it doesn't exist\n if (!current[part] || typeof current[part] !== \"object\") {\n current[part] = {};\n }\n current = current[part];\n }\n }\n }\n }\n\n return config;\n}\n\n/**\n * Parse environment variables into a config object (with consumption report)\n */\nfunction parseEnvVarsWithReport(prefix: string): {\n config: unknown;\n consumedKeys: string[];\n} {\n // biome-ignore lint/suspicious/noExplicitAny: Config object is dynamically constructed\n const config: any = {};\n const consumedKeys: string[] = [];\n const prefixWithSeparator = `${prefix}_`;\n\n for (const [key, value] of Object.entries(process.env)) {\n if (!value) continue;\n\n if (key.startsWith(prefixWithSeparator)) {\n consumedKeys.push(key);\n\n const keyWithoutPrefix = key.slice(prefixWithSeparator.length);\n const parts = keyWithoutPrefix.split(\"_\").filter((p) => p.length > 0);\n\n let current = config;\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i].toLowerCase();\n\n if (i === parts.length - 1) {\n current[part] = parseEnvValue(value);\n } else {\n if (!current[part] || typeof current[part] !== \"object\") {\n current[part] = {};\n }\n current = current[part];\n }\n }\n }\n }\n\n consumedKeys.sort();\n return { config, consumedKeys };\n}\n\n/**\n * Parse a configuration file based on its extension\n */\n// biome-ignore lint/suspicious/noExplicitAny: Parsed config is untyped\nasync function parseConfigFile(path: string): Promise<any> {\n const content = await readFile(path, \"utf-8\");\n const ext = extname(path).toLowerCase();\n\n if (ext === \".json\") {\n return JSON.parse(content);\n }\n\n if (ext === \".yaml\" || ext === \".yml\") {\n return parse(content);\n }\n\n throw new Error(`Unsupported config file extension: ${ext}`);\n}\n\n/**\n * Load configuration using the Three-Layer pattern:\n * 1. Defaults (required) — from a file path ({@link LoadConfigOptions}) or\n * inline content ({@link LoadInlineConfigOptions})\n * 2. User Config (optional, XDG-compliant)\n * 3. Environment Variables (optional, prefix-based)\n */\nexport async function loadConfig<T>(options: LoadConfigOptions): Promise<LoadedConfig<T>>;\nexport async function loadConfig<T>(options: LoadInlineConfigOptions): Promise<LoadedConfig<T>>;\nexport async function loadConfig<T>(\n options: LoadConfigOptions | LoadInlineConfigOptions,\n): Promise<LoadedConfig<T>> {\n const { identity, defaultsPath, defaults, userConfigName } = options;\n const activeLayers: string[] = [\"defaults\"];\n\n // Layer 1: Defaults (inline content takes precedence over a file path)\n let mergedConfig: Record<string, unknown>;\n if (defaults !== undefined) {\n // Clone so callers' embedded objects are never mutated by deepMerge\n mergedConfig = structuredClone(defaults);\n } else if (defaultsPath) {\n mergedConfig = await parseConfigFile(defaultsPath);\n } else {\n throw new Error(\"loadConfig requires either `defaults` (inline) or `defaultsPath`\");\n }\n\n // Layer 2: User Config\n const configName = userConfigName || identity.app; // Simple fallback, assuming identity.app is suitable\n\n // We use resolveConfigPath which expects a filename and search paths.\n // But we support multiple extensions (.yaml, .yml, .json).\n // We iterate through extensions and try to find the file.\n\n const extensions = [\".yaml\", \".yml\", \".json\"];\n let userConfigPath: string | null = null;\n\n const paths = getConfigSearchPaths(identity);\n\n for (const ext of extensions) {\n const filename = `${configName}${ext}`;\n const foundPath = await resolveConfigPath(filename, paths);\n if (foundPath) {\n userConfigPath = foundPath;\n break;\n }\n }\n\n if (userConfigPath) {\n const userConfig = await parseConfigFile(userConfigPath);\n mergedConfig = deepMerge(mergedConfig, userConfig);\n activeLayers.push(\"user\");\n }\n\n // Phase 2: Env Overrides\n const envPrefix =\n options.envPrefix || (identity.app ? identity.app.toUpperCase().replace(/-/g, \"_\") : \"APP\");\n\n const includeEnvVarReport = options.includeEnvVarReport === true;\n const envVars = includeEnvVarReport ? parseEnvVarsWithReport(envPrefix) : null;\n const envConfig = includeEnvVarReport ? envVars?.config : parseEnvVars(envPrefix);\n\n if (\n envConfig &&\n typeof envConfig === \"object\" &&\n Object.keys(envConfig as Record<string, unknown>).length > 0\n ) {\n mergedConfig = deepMerge(mergedConfig, envConfig);\n activeLayers.push(\"env\");\n }\n\n // Phase 3: Validation (inline schema content takes precedence over a file path)\n const schemaProvided = options.schema !== undefined || options.schemaPath !== undefined;\n if (schemaProvided) {\n try {\n const schemaContent =\n options.schema !== undefined\n ? options.schema\n : await readFile(options.schemaPath as string, \"utf-8\");\n const validator = await compileSchema(schemaContent);\n const result = validateData(mergedConfig, validator);\n\n if (!result.valid) {\n throw new ConfigValidationError(\"Configuration validation failed\", result.diagnostics);\n }\n\n // We modify the metadata object that will be returned\n // (Since we return a new object literal below, we just set the property in the return statement)\n } catch (error) {\n if (error instanceof ConfigValidationError) {\n throw error;\n }\n throw new ConfigValidationError(\n `Failed to validate configuration: ${(error as Error).message}`,\n undefined,\n error as Error,\n );\n }\n }\n\n return {\n config: mergedConfig as T,\n metadata: {\n defaultsPath: defaults !== undefined ? \"\" : (defaultsPath as string),\n defaultsSource: defaults !== undefined ? \"inline\" : \"path\",\n userConfigPath,\n envPrefix,\n envVarsConsumed: includeEnvVarReport ? envVars?.consumedKeys : undefined,\n envVarsConsumedCount: includeEnvVarReport ? envVars?.consumedKeys.length : undefined,\n activeLayers,\n schema: {\n // Inline schema wins over schemaPath, and has no backing file → report null.\n path: options.schema !== undefined ? null : (options.schemaPath ?? null),\n source: options.schema !== undefined ? \"inline\" : options.schemaPath ? \"path\" : null,\n validated: schemaProvided,\n },\n },\n };\n}\n","/**\n * Config Path API - implements Fulmen Config Path Standard\n *\n * Provides cross-platform directory resolution for Fulmen configuration, data, and cache directories\n * with XDG Base Directory specification compliance.\n */\n\nimport { access, mkdir } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { isAbsolute, join, resolve } from \"node:path\";\nimport { metrics } from \"../telemetry/index.js\";\nimport { ConfigPathError } from \"./errors.js\";\nimport type { AppIdentifier, ConfigPathOptions, PlatformDirs, XDGBaseDirs } from \"./types.js\";\n\n/**\n * Get platform information and environment variables\n */\nfunction getPlatformInfo(): PlatformDirs {\n const osPlatform = process.platform;\n const homeDir = homedir();\n\n if (!homeDir) {\n throw ConfigPathError.homeDirNotFound();\n }\n\n const platformInfo: PlatformDirs = {\n platform:\n osPlatform === \"linux\"\n ? \"linux\"\n : osPlatform === \"darwin\"\n ? \"darwin\"\n : osPlatform === \"win32\"\n ? \"win32\"\n : \"unknown\",\n homeDir,\n };\n\n // XDG environment variables (Linux/Unix)\n if (osPlatform === \"linux\") {\n platformInfo.xdgEnv = {\n XDG_CONFIG_HOME: process.env.XDG_CONFIG_HOME,\n XDG_DATA_HOME: process.env.XDG_DATA_HOME,\n XDG_CACHE_HOME: process.env.XDG_CACHE_HOME,\n };\n }\n\n // Windows environment variables\n if (osPlatform === \"win32\") {\n platformInfo.winEnv = {\n APPDATA: process.env.APPDATA,\n LOCALAPPDATA: process.env.LOCALAPPDATA,\n };\n }\n\n return platformInfo;\n}\n\n/**\n * Validate vendor and app names according to kebab-case convention\n */\nfunction validateKebabCase(name: string, type: \"vendor\" | \"app\"): void {\n if (!name || typeof name !== \"string\") {\n throw ConfigPathError.invalidName(name, type);\n }\n\n // Must be lowercase and contain only letters, numbers, and hyphens\n if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(name)) {\n throw ConfigPathError.invalidName(name, type);\n }\n}\n\n/**\n * Validate application identifier\n */\nfunction validateAppIdentifier(app: AppIdentifier): void {\n if (!app || typeof app !== \"object\") {\n throw ConfigPathError.invalidAppIdentifier(app);\n }\n\n if (!app.vendor || !app.app) {\n throw ConfigPathError.invalidAppIdentifier(app);\n }\n\n validateKebabCase(app.vendor, \"vendor\");\n validateKebabCase(app.app, \"app\");\n}\n\n/**\n * Validate environment variable override path\n */\nfunction validateEnvVarPath(path: string, varName: string, homeDir: string): void {\n if (!isAbsolute(path)) {\n throw ConfigPathError.invalidEnvVar(varName, path);\n }\n\n // Security: ensure path is within home directory unless explicitly allowed\n // Normalize paths for case-insensitive comparison on Windows\n const resolvedPath = resolve(path);\n const resolvedHome = resolve(homeDir);\n\n // Case-insensitive comparison for Windows, case-sensitive for Unix-like systems\n const isWindows = process.platform === \"win32\";\n const normalizedPath = isWindows ? resolvedPath.toLowerCase() : resolvedPath;\n const normalizedHome = isWindows ? resolvedHome.toLowerCase() : resolvedHome;\n\n if (!normalizedPath.startsWith(normalizedHome)) {\n throw ConfigPathError.invalidEnvVar(varName, path);\n }\n}\n\n/**\n * Get XDG base directories with environment variable overrides\n */\nexport function getXDGBaseDirs(options: ConfigPathOptions = {}): XDGBaseDirs {\n const platformInfo = getPlatformInfo();\n const homeDir = options.customHomeDir || platformInfo.homeDir;\n\n // Environment variable overrides take precedence\n const configHome =\n process.env.FULMEN_CONFIG_HOME || process.env.XDG_CONFIG_HOME || join(homeDir, \".config\");\n\n const dataHome =\n process.env.FULMEN_DATA_HOME || process.env.XDG_DATA_HOME || join(homeDir, \".local\", \"share\");\n\n const cacheHome =\n process.env.FULMEN_CACHE_HOME || process.env.XDG_CACHE_HOME || join(homeDir, \".cache\");\n\n // Validate environment variable overrides\n if (process.env.FULMEN_CONFIG_HOME) {\n validateEnvVarPath(configHome, \"FULMEN_CONFIG_HOME\", homeDir);\n }\n if (process.env.FULMEN_DATA_HOME) {\n validateEnvVarPath(dataHome, \"FULMEN_DATA_HOME\", homeDir);\n }\n if (process.env.FULMEN_CACHE_HOME) {\n validateEnvVarPath(cacheHome, \"FULMEN_CACHE_HOME\", homeDir);\n }\n\n return {\n configHome,\n dataHome,\n cacheHome,\n };\n}\n\n/**\n * Get platform-specific base directories\n */\nfunction getPlatformBaseDirs(options: ConfigPathOptions = {}): XDGBaseDirs {\n const platformInfo = getPlatformInfo();\n const homeDir = options.customHomeDir || platformInfo.homeDir;\n\n switch (platformInfo.platform) {\n case \"darwin\": {\n // macOS: ~/Library/Application Support for config and data\n const appSupport = join(homeDir, \"Library\", \"Application Support\");\n const cacheSupport = join(homeDir, \"Library\", \"Caches\");\n\n // Start with platform defaults\n let configHome = appSupport;\n let dataHome = appSupport;\n let cacheHome = cacheSupport;\n\n // Apply environment variable overrides with validation\n if (process.env.FULMEN_CONFIG_HOME) {\n validateEnvVarPath(process.env.FULMEN_CONFIG_HOME, \"FULMEN_CONFIG_HOME\", homeDir);\n configHome = process.env.FULMEN_CONFIG_HOME;\n }\n if (process.env.FULMEN_DATA_HOME) {\n validateEnvVarPath(process.env.FULMEN_DATA_HOME, \"FULMEN_DATA_HOME\", homeDir);\n dataHome = process.env.FULMEN_DATA_HOME;\n }\n if (process.env.FULMEN_CACHE_HOME) {\n validateEnvVarPath(process.env.FULMEN_CACHE_HOME, \"FULMEN_CACHE_HOME\", homeDir);\n cacheHome = process.env.FULMEN_CACHE_HOME;\n }\n\n return { configHome, dataHome, cacheHome };\n }\n\n case \"win32\": {\n // Windows: %APPDATA% for config, %LOCALAPPDATA% for data and cache\n const appData = platformInfo.winEnv?.APPDATA || join(homeDir, \"AppData\", \"Roaming\");\n const localAppData = platformInfo.winEnv?.LOCALAPPDATA || join(homeDir, \"AppData\", \"Local\");\n const cacheDir = join(localAppData, \"Cache\");\n\n // Start with platform defaults\n let configHome = appData;\n let dataHome = localAppData;\n let cacheHome = cacheDir;\n\n // Apply environment variable overrides with validation\n if (process.env.FULMEN_CONFIG_HOME) {\n validateEnvVarPath(process.env.FULMEN_CONFIG_HOME, \"FULMEN_CONFIG_HOME\", homeDir);\n configHome = process.env.FULMEN_CONFIG_HOME;\n }\n if (process.env.FULMEN_DATA_HOME) {\n validateEnvVarPath(process.env.FULMEN_DATA_HOME, \"FULMEN_DATA_HOME\", homeDir);\n dataHome = process.env.FULMEN_DATA_HOME;\n }\n if (process.env.FULMEN_CACHE_HOME) {\n validateEnvVarPath(process.env.FULMEN_CACHE_HOME, \"FULMEN_CACHE_HOME\", homeDir);\n cacheHome = process.env.FULMEN_CACHE_HOME;\n }\n\n return { configHome, dataHome, cacheHome };\n }\n\n case \"linux\":\n // Linux: use XDG (already includes validation)\n return getXDGBaseDirs(options);\n\n default:\n // Fallback: use XDG (Linux-style, already includes validation)\n return getXDGBaseDirs(options);\n }\n}\n\n/**\n * Get Fulmen-specific config directory\n */\nexport function getFulmenConfigDir(options: ConfigPathOptions = {}): string {\n const baseDirs = getPlatformBaseDirs(options);\n return join(baseDirs.configHome, \"fulmen\");\n}\n\n/**\n * Get Fulmen-specific data directory\n */\nexport function getFulmenDataDir(options: ConfigPathOptions = {}): string {\n const baseDirs = getPlatformBaseDirs(options);\n return join(baseDirs.dataHome, \"fulmen\");\n}\n\n/**\n * Get Fulmen-specific cache directory\n */\nexport function getFulmenCacheDir(options: ConfigPathOptions = {}): string {\n const baseDirs = getPlatformBaseDirs(options);\n return join(baseDirs.cacheHome, \"fulmen\");\n}\n\n/**\n * Get application-specific config directory\n */\nexport function getAppConfigDir(app: AppIdentifier, options: ConfigPathOptions = {}): string {\n validateAppIdentifier(app);\n const fulmenConfig = getFulmenConfigDir(options);\n return join(fulmenConfig, app.vendor, app.app);\n}\n\n/**\n * Get application-specific data directory\n */\nexport function getAppDataDir(app: AppIdentifier, options: ConfigPathOptions = {}): string {\n validateAppIdentifier(app);\n const fulmenData = getFulmenDataDir(options);\n return join(fulmenData, app.vendor, app.app);\n}\n\n/**\n * Get application-specific cache directory\n */\nexport function getAppCacheDir(app: AppIdentifier, options: ConfigPathOptions = {}): string {\n validateAppIdentifier(app);\n const fulmenCache = getFulmenCacheDir(options);\n return join(fulmenCache, app.vendor, app.app);\n}\n\n/**\n * Get ordered list of config search paths for an application\n */\nexport function getConfigSearchPaths(\n app: AppIdentifier,\n options: ConfigPathOptions = {},\n): string[] {\n validateAppIdentifier(app);\n\n const paths: string[] = [];\n\n // 1. Application-specific config directory (highest priority)\n paths.push(getAppConfigDir(app, options));\n\n // 2. Fulmen-wide config directory\n paths.push(getFulmenConfigDir(options));\n\n // 3. Legacy names for migration support\n if (options.legacyNames) {\n for (const legacyName of options.legacyNames) {\n const baseDirs = getPlatformBaseDirs(options);\n paths.push(join(baseDirs.configHome, legacyName));\n }\n }\n\n return paths;\n}\n\n/**\n * Ensure directory exists (create if necessary)\n */\nexport async function ensureDirExists(dirPath: string): Promise<void> {\n const startTime = performance.now();\n\n try {\n await access(dirPath);\n metrics.histogram(\"config_load_ms\").observe(performance.now() - startTime);\n } catch (error) {\n const nodeError = error as NodeJS.ErrnoException;\n if (nodeError.code === \"ENOENT\") {\n try {\n await mkdir(dirPath, { recursive: true });\n metrics.histogram(\"config_load_ms\").observe(performance.now() - startTime);\n } catch (mkdirError) {\n metrics.counter(\"config_load_errors\").inc();\n metrics.histogram(\"config_load_ms\").observe(performance.now() - startTime);\n throw ConfigPathError.directoryCreationFailed(dirPath, mkdirError as Error);\n }\n } else {\n metrics.counter(\"config_load_errors\").inc();\n metrics.histogram(\"config_load_ms\").observe(performance.now() - startTime);\n throw ConfigPathError.directoryCreationFailed(dirPath, nodeError);\n }\n }\n}\n\n/**\n * Resolve config file path with search path logic\n */\nexport async function resolveConfigPath(\n filename: string,\n searchPaths: string[],\n options: { ensureDir?: boolean } = {},\n): Promise<string | null> {\n const startTime = performance.now();\n\n try {\n for (const searchPath of searchPaths) {\n if (options.ensureDir) {\n await ensureDirExists(searchPath);\n }\n\n const fullPath = join(searchPath, filename);\n try {\n await access(fullPath);\n metrics.histogram(\"config_load_ms\").observe(performance.now() - startTime);\n return fullPath;\n } catch (error) {\n const nodeError = error as NodeJS.ErrnoException;\n if (nodeError.code !== \"ENOENT\") {\n metrics.counter(\"config_load_errors\").inc();\n metrics.histogram(\"config_load_ms\").observe(performance.now() - startTime);\n throw error;\n }\n }\n }\n\n metrics.histogram(\"config_load_ms\").observe(performance.now() - startTime);\n return null;\n } catch (error) {\n if (!(error instanceof ConfigPathError)) {\n metrics.counter(\"config_load_errors\").inc();\n metrics.histogram(\"config_load_ms\").observe(performance.now() - startTime);\n }\n throw error;\n }\n}\n","/**\n * Config module - implements Fulmen Config Path Standard\n *\n * Provides utilities for config path resolution and three-layer config loading\n */\n\nexport const VERSION = \"0.1.0\";\n\nexport * from \"./env-alias.js\";\nexport * from \"./errors.js\";\nexport * from \"./loader.js\";\n// Config Path API exports\nexport * from \"./paths.js\";\nexport * from \"./types.js\";\n"]}