@cleocode/caamp 1.8.1 → 1.9.1
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.
- package/dist/chunk-J7UN457C.js +244 -0
- package/dist/chunk-J7UN457C.js.map +1 -0
- package/dist/{chunk-CPHF5IM4.js → chunk-O7IVK5JY.js} +20 -290
- package/dist/chunk-O7IVK5JY.js.map +1 -0
- package/dist/chunk-TI6WOJDG.js +276 -0
- package/dist/chunk-TI6WOJDG.js.map +1 -0
- package/dist/{chunk-LDTYDQGR.js → chunk-ZF4W3K5H.js} +40 -5
- package/dist/chunk-ZF4W3K5H.js.map +1 -0
- package/dist/cli.js +205 -87
- package/dist/cli.js.map +1 -1
- package/dist/hooks-E2XQ7TQG.js +56 -0
- package/dist/index.d.ts +4427 -928
- package/dist/index.js +71 -19
- package/dist/index.js.map +1 -1
- package/dist/{injector-TIUEM4X2.js → injector-NSDP5Z2P.js} +3 -2
- package/dist/injector-NSDP5Z2P.js.map +1 -0
- package/package.json +1 -1
- package/providers/hook-mappings.json +302 -0
- package/providers/registry.json +599 -156
- package/dist/chunk-CPHF5IM4.js.map +0 -1
- package/dist/chunk-LDTYDQGR.js.map +0 -1
- /package/dist/{injector-TIUEM4X2.js.map → hooks-E2XQ7TQG.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/formats/utils.ts","../src/core/logger.ts","../src/core/formats/json.ts","../src/core/formats/yaml.ts","../src/core/formats/toml.ts","../src/core/formats/index.ts","../src/core/mcp/reader.ts","../src/core/mcp/transforms.ts","../src/core/mcp/installer.ts","../src/core/registry/detection.ts","../src/core/skills/installer.ts","../src/core/advanced/orchestration.ts","../src/core/paths/agents.ts","../src/core/mcp/cleo.ts","../src/core/lock-utils.ts","../src/core/mcp/lock.ts","../src/core/mcp/reconcile.ts","../src/core/sources/parser.ts","../src/core/network/fetch.ts","../src/core/marketplace/skillsmp.ts","../src/core/marketplace/skillssh.ts","../src/core/marketplace/client.ts","../src/core/skills/library-loader.ts","../src/core/skills/catalog.ts","../src/core/skills/discovery.ts","../src/core/skills/lock.ts","../src/core/skills/recommendation.ts","../src/core/skills/recommendation-api.ts","../src/core/skills/audit/scanner.ts","../src/core/skills/audit/rules.ts","../src/core/skills/validator.ts"],"sourcesContent":["/**\n * Format utility functions\n */\n\n/**\n * Deep merge two objects, with `source` values winning on conflict.\n *\n * Recursively merges nested plain objects. Arrays and non-object values from\n * `source` overwrite `target` values.\n *\n * @param target - Base object to merge into\n * @param source - Object with values that take precedence\n * @returns A new merged object (does not mutate inputs)\n *\n * @remarks\n * Only plain objects are recursively merged. Arrays and primitive values from\n * `source` replace `target` values outright. Neither input is mutated.\n *\n * @example\n * ```typescript\n * const merged = deepMerge({ a: 1, b: { c: 2 } }, { b: { d: 3 } });\n * // { a: 1, b: { c: 2, d: 3 } }\n * ```\n *\n * @public\n */\nexport function deepMerge(\n target: Record<string, unknown>,\n source: Record<string, unknown>,\n): Record<string, unknown> {\n const result: Record<string, unknown> = { ...target };\n\n for (const key of Object.keys(source)) {\n const sourceVal = source[key];\n const targetVal = target[key];\n\n if (\n sourceVal !== null &&\n typeof sourceVal === \"object\" &&\n !Array.isArray(sourceVal) &&\n targetVal !== null &&\n typeof targetVal === \"object\" &&\n !Array.isArray(targetVal)\n ) {\n result[key] = deepMerge(\n targetVal as Record<string, unknown>,\n sourceVal as Record<string, unknown>,\n );\n } else {\n result[key] = sourceVal;\n }\n }\n\n return result;\n}\n\n/**\n * Set a nested value using a dot-notation key path.\n *\n * @remarks\n * Creates intermediate objects as needed. Returns a shallow copy of the\n * root object (does not mutate the input).\n *\n * @param obj - Root object to modify\n * @param keyPath - Dot-separated path to the parent key (e.g. `\"mcpServers\"`)\n * @param key - Final key name for the value\n * @param value - Value to set at the nested location\n * @returns A new object with the value set at the specified path\n *\n * @example\n * ```typescript\n * const result = setNestedValue({}, \"a.b\", \"c\", 42);\n * // { a: { b: { c: 42 } } }\n * ```\n *\n * @public\n */\nexport function setNestedValue(\n obj: Record<string, unknown>,\n keyPath: string,\n key: string,\n value: unknown,\n): Record<string, unknown> {\n const parts = keyPath.split(\".\");\n const result = { ...obj };\n let current: Record<string, unknown> = result;\n\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i];\n if (part === undefined) continue;\n if (i === parts.length - 1) {\n // Last part: set the server entry\n const existing = (current[part] as Record<string, unknown>) ?? {};\n current[part] = { ...existing, [key]: value };\n } else {\n // Intermediate: ensure object exists\n if (typeof current[part] !== \"object\" || current[part] === null) {\n current[part] = {};\n }\n current[part] = { ...(current[part] as Record<string, unknown>) };\n current = current[part] as Record<string, unknown>;\n }\n }\n\n return result;\n}\n\n/**\n * Get a nested value from an object using a dot-notation key path.\n *\n * @param obj - Object to traverse\n * @param keyPath - Dot-separated key path (e.g. `\"mcpServers\"` or `\"a.b.c\"`)\n * @returns The value at the key path, or `undefined` if not found\n *\n * @remarks\n * Splits the key path on `.` and walks the object tree. Returns `undefined`\n * at the first missing or non-object segment.\n *\n * @example\n * ```typescript\n * getNestedValue({ a: { b: { c: 42 } } }, \"a.b.c\"); // 42\n * getNestedValue({ a: 1 }, \"a.b\"); // undefined\n * ```\n *\n * @public\n */\nexport function getNestedValue(\n obj: Record<string, unknown>,\n keyPath: string,\n): unknown {\n const parts = keyPath.split(\".\");\n let current: unknown = obj;\n\n for (const part of parts) {\n if (current === null || typeof current !== \"object\") return undefined;\n current = (current as Record<string, unknown>)[part];\n }\n\n return current;\n}\n\n/**\n * Ensure that the parent directories of a file path exist.\n *\n * Creates directories recursively if they do not exist.\n *\n * @param filePath - Absolute path to a file (parent directories will be created)\n *\n * @remarks\n * Uses `mkdir` with `recursive: true` so existing directories are not an error.\n *\n * @example\n * ```typescript\n * await ensureDir(\"/path/to/new/dir/file.json\");\n * // /path/to/new/dir/ now exists\n * ```\n *\n * @public\n */\nexport async function ensureDir(filePath: string): Promise<void> {\n const { mkdir } = await import(\"node:fs/promises\");\n const { dirname } = await import(\"node:path\");\n await mkdir(dirname(filePath), { recursive: true });\n}\n","/**\n * Simple logger with verbose/quiet mode support.\n *\n * - verbose: enables debug output to stderr\n * - quiet: suppresses info and warn output (errors always shown)\n */\n\nlet verboseMode = false;\nlet quietMode = false;\nlet humanMode = false;\n\n/**\n * Enable or disable verbose (debug) logging mode.\n *\n * When enabled, debug messages are written to stderr.\n *\n * @param v - `true` to enable verbose mode, `false` to disable\n *\n * @remarks\n * Typically called once during CLI initialization based on the `--verbose` flag.\n *\n * @example\n * ```typescript\n * setVerbose(true);\n * ```\n *\n * @public\n */\nexport function setVerbose(v: boolean): void {\n verboseMode = v;\n}\n\n/**\n * Enable or disable quiet mode.\n *\n * When enabled, info and warning messages are suppressed. Errors are always shown.\n *\n * @param q - `true` to enable quiet mode, `false` to disable\n *\n * @remarks\n * Typically called once during CLI initialization based on the `--quiet` flag.\n *\n * @example\n * ```typescript\n * setQuiet(true);\n * ```\n *\n * @public\n */\nexport function setQuiet(q: boolean): void {\n quietMode = q;\n}\n\n/**\n * Log a debug message to stderr when verbose mode is enabled.\n *\n * @remarks\n * Messages are prefixed with `[debug]` and written to stderr. No output is\n * produced when verbose mode is disabled.\n *\n * @param args - Values to log (forwarded to `console.error`)\n *\n * @example\n * ```typescript\n * debug(\"Loading config from\", filePath);\n * ```\n *\n * @public\n */\nexport function debug(...args: unknown[]): void {\n if (verboseMode) console.error(\"[debug]\", ...args);\n}\n\n/**\n * Log an informational message to stdout.\n *\n * @remarks\n * Output is suppressed when quiet mode is enabled.\n *\n * @param args - Values to log (forwarded to `console.log`)\n *\n * @example\n * ```typescript\n * info(\"Installed 3 skills\");\n * ```\n *\n * @public\n */\nexport function info(...args: unknown[]): void {\n if (!quietMode) console.log(...args);\n}\n\n/**\n * Log a warning message to stderr.\n *\n * @remarks\n * Output is suppressed when quiet mode is enabled.\n *\n * @param args - Values to log (forwarded to `console.warn`)\n *\n * @example\n * ```typescript\n * warn(\"Deprecated option used\");\n * ```\n *\n * @public\n */\nexport function warn(...args: unknown[]): void {\n if (!quietMode) console.warn(...args);\n}\n\n/**\n * Log an error message to stderr.\n *\n * @remarks\n * Errors are always displayed regardless of quiet mode.\n *\n * @param args - Values to log (forwarded to `console.error`)\n *\n * @example\n * ```typescript\n * error(\"Failed to install skill:\", err.message);\n * ```\n *\n * @public\n */\nexport function error(...args: unknown[]): void {\n console.error(...args);\n}\n\n/**\n * Check if verbose (debug) logging is currently enabled.\n *\n * @remarks\n * Useful for conditionally performing expensive formatting only when verbose\n * output is requested.\n *\n * @returns `true` if verbose mode is active\n *\n * @example\n * ```typescript\n * if (isVerbose()) {\n * console.error(\"Extra debug info\");\n * }\n * ```\n *\n * @public\n */\nexport function isVerbose(): boolean {\n return verboseMode;\n}\n\n/**\n * Check if quiet mode is currently enabled.\n *\n * @remarks\n * Commands use this to skip non-essential output when the user requested quiet\n * operation.\n *\n * @returns `true` if quiet mode is active\n *\n * @example\n * ```typescript\n * if (!isQuiet()) {\n * console.log(\"Status message\");\n * }\n * ```\n *\n * @public\n */\nexport function isQuiet(): boolean {\n return quietMode;\n}\n\n/**\n * Enable or disable human-readable output mode.\n *\n * When enabled, commands output human-readable format instead of JSON.\n *\n * @param h - `true` to enable human mode, `false` to disable\n *\n * @remarks\n * Typically called once during CLI initialization based on the `--human` flag.\n *\n * @example\n * ```typescript\n * setHuman(true);\n * ```\n *\n * @public\n */\nexport function setHuman(h: boolean): void {\n humanMode = h;\n}\n\n/**\n * Check if human-readable output mode is currently enabled.\n *\n * @remarks\n * Commands use this to decide between structured JSON output and\n * human-friendly formatted output.\n *\n * @returns `true` if human mode is active\n *\n * @example\n * ```typescript\n * if (isHuman()) {\n * console.log(\"Human readable output\");\n * } else {\n * console.log(JSON.stringify(data));\n * }\n * ```\n *\n * @public\n */\nexport function isHuman(): boolean {\n return humanMode;\n}\n","/**\n * JSON/JSONC config reader/writer with comment preservation\n *\n * Uses jsonc-parser for surgical edits that preserve comments,\n * formatting, and trailing commas in JSONC files.\n */\n\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport * as jsonc from \"jsonc-parser\";\nimport { ensureDir } from \"./utils.js\";\n\n/**\n * Read and parse a JSON or JSONC config file.\n *\n * @remarks\n * Uses `jsonc-parser` to handle JSONC features (comments, trailing commas).\n * Returns an empty object when the file does not exist or is empty.\n *\n * @param filePath - Absolute path to the JSON/JSONC file\n * @returns Parsed config object\n *\n * @example\n * ```typescript\n * const config = await readJsonConfig(\"/home/user/.config/claude/settings.json\");\n * ```\n *\n * @public\n */\nexport async function readJsonConfig(filePath: string): Promise<Record<string, unknown>> {\n if (!existsSync(filePath)) return {};\n\n const content = await readFile(filePath, \"utf-8\");\n if (!content.trim()) return {};\n\n const errors: jsonc.ParseError[] = [];\n const result = jsonc.parse(content, errors);\n\n if (errors.length > 0) {\n // Fall back to standard JSON parse for better error messages\n return JSON.parse(content) as Record<string, unknown>;\n }\n\n return (result ?? {}) as Record<string, unknown>;\n}\n\n/** Detect indentation from existing file content */\nfunction detectIndent(content: string): { indent: string; insertSpaces: boolean; tabSize: number } {\n const lines = content.split(\"\\n\");\n for (const line of lines) {\n const match = line.match(/^(\\s+)/);\n if (match?.[1]) {\n const ws = match[1];\n if (ws.startsWith(\"\\t\")) {\n return { indent: \"\\t\", insertSpaces: false, tabSize: 1 };\n }\n return { indent: ws, insertSpaces: true, tabSize: ws.length };\n }\n }\n return { indent: \" \", insertSpaces: true, tabSize: 2 };\n}\n\n/**\n * Write a server config entry to a JSON/JSONC file, preserving comments.\n *\n * @remarks\n * Uses `jsonc-parser.modify` for surgical edits that preserve comments,\n * formatting, and trailing commas. Creates the file if it does not exist.\n *\n * @param filePath - Absolute path to the JSON/JSONC file\n * @param configKey - Dot-notation key path to the servers section (e.g. `\"mcpServers\"`)\n * @param serverName - Name/key for the server entry\n * @param serverConfig - Server configuration object to write\n *\n * @example\n * ```typescript\n * await writeJsonConfig(\"/path/to/config.json\", \"mcpServers\", \"my-server\", { command: \"node\" });\n * ```\n *\n * @public\n */\nexport async function writeJsonConfig(\n filePath: string,\n configKey: string,\n serverName: string,\n serverConfig: unknown,\n): Promise<void> {\n await ensureDir(filePath);\n\n let content: string;\n\n if (existsSync(filePath)) {\n content = await readFile(filePath, \"utf-8\");\n if (!content.trim()) {\n content = \"{}\";\n }\n } else {\n content = \"{}\";\n }\n\n const { tabSize, insertSpaces } = detectIndent(content);\n\n const formatOptions: jsonc.FormattingOptions = {\n tabSize,\n insertSpaces,\n eol: \"\\n\",\n };\n\n // Build the JSON path for the server entry\n const keyParts = configKey.split(\".\");\n const jsonPath = [...keyParts, serverName];\n\n // Use jsonc.modify for surgical, comment-preserving edits\n const edits = jsonc.modify(content, jsonPath, serverConfig, { formattingOptions: formatOptions });\n\n if (edits.length > 0) {\n content = jsonc.applyEdits(content, edits);\n }\n\n // Ensure trailing newline\n if (!content.endsWith(\"\\n\")) {\n content += \"\\n\";\n }\n\n await writeFile(filePath, content, \"utf-8\");\n}\n\n/**\n * Remove a server entry from a JSON/JSONC config file.\n *\n * @remarks\n * Uses `jsonc-parser.modify` with `undefined` value to remove the key while\n * preserving surrounding comments and formatting.\n *\n * @param filePath - Absolute path to the JSON/JSONC file\n * @param configKey - Dot-notation key path to the servers section\n * @param serverName - Name/key of the server entry to remove\n * @returns `true` if the entry was removed, `false` if the file or entry was not found\n *\n * @example\n * ```typescript\n * const removed = await removeJsonConfig(\"/path/to/config.json\", \"mcpServers\", \"old-server\");\n * ```\n *\n * @public\n */\nexport async function removeJsonConfig(\n filePath: string,\n configKey: string,\n serverName: string,\n): Promise<boolean> {\n if (!existsSync(filePath)) return false;\n\n let content = await readFile(filePath, \"utf-8\");\n if (!content.trim()) return false;\n\n const { tabSize, insertSpaces } = detectIndent(content);\n\n const formatOptions: jsonc.FormattingOptions = {\n tabSize,\n insertSpaces,\n eol: \"\\n\",\n };\n\n const keyParts = configKey.split(\".\");\n const jsonPath = [...keyParts, serverName];\n\n const edits = jsonc.modify(content, jsonPath, undefined, { formattingOptions: formatOptions });\n\n if (edits.length === 0) return false;\n\n content = jsonc.applyEdits(content, edits);\n\n if (!content.endsWith(\"\\n\")) {\n content += \"\\n\";\n }\n\n await writeFile(filePath, content, \"utf-8\");\n return true;\n}\n","/**\n * YAML config reader/writer\n */\n\nimport { existsSync } from \"node:fs\";\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport yaml from \"js-yaml\";\nimport { deepMerge, ensureDir } from \"./utils.js\";\n\n/**\n * Read and parse a YAML config file.\n *\n * @remarks\n * Uses `js-yaml` for parsing. Returns an empty object when the file does not\n * exist or is empty.\n *\n * @param filePath - Absolute path to the YAML file\n * @returns Parsed config object\n *\n * @example\n * ```typescript\n * const config = await readYamlConfig(\"/path/to/config.yaml\");\n * ```\n *\n * @public\n */\nexport async function readYamlConfig(filePath: string): Promise<Record<string, unknown>> {\n if (!existsSync(filePath)) return {};\n\n const content = await readFile(filePath, \"utf-8\");\n if (!content.trim()) return {};\n\n const result = yaml.load(content);\n return (result ?? {}) as Record<string, unknown>;\n}\n\n/**\n * Write a server config entry to a YAML file.\n *\n * @remarks\n * Reads the existing file, deep-merges the new entry, and writes the entire\n * result back. Creates the file and parent directories if they do not exist.\n *\n * @param filePath - Absolute path to the YAML file\n * @param configKey - Dot-notation key path to the servers section\n * @param serverName - Name/key for the server entry\n * @param serverConfig - Server configuration object to write\n *\n * @example\n * ```typescript\n * await writeYamlConfig(\"/path/to/config.yaml\", \"mcpServers\", \"my-server\", { command: \"node\" });\n * ```\n *\n * @public\n */\nexport async function writeYamlConfig(\n filePath: string,\n configKey: string,\n serverName: string,\n serverConfig: unknown,\n): Promise<void> {\n await ensureDir(filePath);\n\n const existing = await readYamlConfig(filePath);\n\n // Build nested structure\n const keyParts = configKey.split(\".\");\n let newEntry: Record<string, unknown> = { [serverName]: serverConfig };\n\n for (const part of [...keyParts].reverse()) {\n newEntry = { [part]: newEntry };\n }\n\n const merged = deepMerge(existing, newEntry);\n\n const content = yaml.dump(merged, {\n indent: 2,\n lineWidth: -1,\n noRefs: true,\n sortKeys: false,\n });\n\n await writeFile(filePath, content, \"utf-8\");\n}\n\n/**\n * Remove a server entry from a YAML config file.\n *\n * @remarks\n * Navigates the parsed YAML object to the config key, deletes the server\n * entry, and re-serializes the entire config.\n *\n * @param filePath - Absolute path to the YAML file\n * @param configKey - Dot-notation key path to the servers section\n * @param serverName - Name/key of the server entry to remove\n * @returns `true` if the entry was removed, `false` if the file or entry was not found\n *\n * @example\n * ```typescript\n * const removed = await removeYamlConfig(\"/path/to/config.yaml\", \"mcpServers\", \"old-server\");\n * ```\n *\n * @public\n */\nexport async function removeYamlConfig(\n filePath: string,\n configKey: string,\n serverName: string,\n): Promise<boolean> {\n if (!existsSync(filePath)) return false;\n\n const existing = await readYamlConfig(filePath);\n\n // Navigate to the config key\n const keyParts = configKey.split(\".\");\n let current: Record<string, unknown> = existing;\n\n for (const part of keyParts) {\n const next = current[part];\n if (typeof next !== \"object\" || next === null) return false;\n current = next as Record<string, unknown>;\n }\n\n if (!(serverName in current)) return false;\n\n delete current[serverName];\n\n const content = yaml.dump(existing, {\n indent: 2,\n lineWidth: -1,\n noRefs: true,\n sortKeys: false,\n });\n\n await writeFile(filePath, content, \"utf-8\");\n return true;\n}\n","/**\n * TOML config reader/writer\n */\n\nimport { existsSync } from \"node:fs\";\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport TOML from \"@iarna/toml\";\nimport { deepMerge, ensureDir } from \"./utils.js\";\n\n/**\n * Read and parse a TOML config file.\n *\n * @remarks\n * Uses `@iarna/toml` for parsing. Returns an empty object when the file does\n * not exist or is empty.\n *\n * @param filePath - Absolute path to the TOML file\n * @returns Parsed config object\n *\n * @example\n * ```typescript\n * const config = await readTomlConfig(\"/path/to/config.toml\");\n * ```\n *\n * @public\n */\nexport async function readTomlConfig(filePath: string): Promise<Record<string, unknown>> {\n if (!existsSync(filePath)) return {};\n\n const content = await readFile(filePath, \"utf-8\");\n if (!content.trim()) return {};\n\n const result = TOML.parse(content);\n return result as unknown as Record<string, unknown>;\n}\n\n/**\n * Write a server config entry to a TOML file.\n *\n * @remarks\n * Reads the existing file, deep-merges the new entry, and writes the entire\n * result back. Creates the file and parent directories if they do not exist.\n *\n * @param filePath - Absolute path to the TOML file\n * @param configKey - Dot-notation key path to the servers section\n * @param serverName - Name/key for the server entry\n * @param serverConfig - Server configuration object to write\n *\n * @example\n * ```typescript\n * await writeTomlConfig(\"/path/to/config.toml\", \"mcpServers\", \"my-server\", { command: \"node\" });\n * ```\n *\n * @public\n */\nexport async function writeTomlConfig(\n filePath: string,\n configKey: string,\n serverName: string,\n serverConfig: unknown,\n): Promise<void> {\n await ensureDir(filePath);\n\n const existing = await readTomlConfig(filePath);\n\n // Build nested structure\n const keyParts = configKey.split(\".\");\n let newEntry: Record<string, unknown> = { [serverName]: serverConfig };\n\n for (const part of [...keyParts].reverse()) {\n newEntry = { [part]: newEntry };\n }\n\n const merged = deepMerge(existing, newEntry);\n\n const content = TOML.stringify(merged as TOML.JsonMap);\n\n await writeFile(filePath, content, \"utf-8\");\n}\n\n/**\n * Remove a server entry from a TOML config file.\n *\n * @remarks\n * Navigates the parsed TOML object to the config key, deletes the server\n * entry, and re-serializes the entire config.\n *\n * @param filePath - Absolute path to the TOML file\n * @param configKey - Dot-notation key path to the servers section\n * @param serverName - Name/key of the server entry to remove\n * @returns `true` if the entry was removed, `false` if the file or entry was not found\n *\n * @example\n * ```typescript\n * const removed = await removeTomlConfig(\"/path/to/config.toml\", \"mcpServers\", \"old-server\");\n * ```\n *\n * @public\n */\nexport async function removeTomlConfig(\n filePath: string,\n configKey: string,\n serverName: string,\n): Promise<boolean> {\n if (!existsSync(filePath)) return false;\n\n const existing = await readTomlConfig(filePath);\n\n const keyParts = configKey.split(\".\");\n let current: Record<string, unknown> = existing;\n\n for (const part of keyParts) {\n const next = current[part];\n if (typeof next !== \"object\" || next === null) return false;\n current = next as Record<string, unknown>;\n }\n\n if (!(serverName in current)) return false;\n\n delete current[serverName];\n\n const content = TOML.stringify(existing as TOML.JsonMap);\n\n await writeFile(filePath, content, \"utf-8\");\n return true;\n}\n","/**\n * Provides format-agnostic config read, write, and remove operations that\n * dispatch to JSON/JSONC, YAML, or TOML handlers based on the specified\n * format.\n *\n * @packageDocumentation\n */\n\nimport type { ConfigFormat } from \"../../types.js\";\nimport { readJsonConfig, writeJsonConfig, removeJsonConfig } from \"./json.js\";\nimport { readYamlConfig, writeYamlConfig, removeYamlConfig } from \"./yaml.js\";\nimport { readTomlConfig, writeTomlConfig, removeTomlConfig } from \"./toml.js\";\nimport { debug } from \"../logger.js\";\n\nexport { deepMerge, getNestedValue, ensureDir } from \"./utils.js\";\n\n/**\n * Read and parse a config file in the specified format.\n *\n * Dispatches to the appropriate format handler (JSON/JSONC, YAML, or TOML).\n *\n * @param filePath - Absolute path to the config file\n * @param format - Config file format\n * @returns Parsed config object\n * @throws If the file cannot be read or the format is unsupported\n *\n * @remarks\n * Supported formats: `\"json\"`, `\"jsonc\"`, `\"yaml\"`, `\"toml\"`. Throws for\n * any unrecognized format string.\n *\n * @example\n * ```typescript\n * const config = await readConfig(\"/path/to/config.json\", \"jsonc\");\n * ```\n *\n * @public\n */\nexport async function readConfig(filePath: string, format: ConfigFormat): Promise<Record<string, unknown>> {\n debug(`reading config: ${filePath} (format: ${format})`);\n switch (format) {\n case \"json\":\n case \"jsonc\":\n return readJsonConfig(filePath);\n case \"yaml\":\n return readYamlConfig(filePath);\n case \"toml\":\n return readTomlConfig(filePath);\n default:\n throw new Error(`Unsupported config format: ${format as string}`);\n }\n}\n\n/**\n * Write a server entry to a config file, preserving existing content.\n *\n * Dispatches to the appropriate format handler. For JSONC files, comments are\n * preserved using `jsonc-parser`.\n *\n * @param filePath - Absolute path to the config file\n * @param format - Config file format\n * @param key - Dot-notation key path to the servers section (e.g. `\"mcpServers\"`)\n * @param serverName - Name/key for the server entry\n * @param serverConfig - Server configuration object to write\n * @throws If the format is unsupported\n *\n * @remarks\n * For JSONC files, comments and formatting are preserved using `jsonc-parser`.\n * For YAML and TOML, the file is fully re-serialized after deep-merging.\n *\n * @example\n * ```typescript\n * await writeConfig(\"/path/to/config.json\", \"jsonc\", \"mcpServers\", \"my-server\", config);\n * ```\n *\n * @public\n */\nexport async function writeConfig(\n filePath: string,\n format: ConfigFormat,\n key: string,\n serverName: string,\n serverConfig: unknown,\n): Promise<void> {\n debug(`writing config: ${filePath} (format: ${format}, key: ${key}, server: ${serverName})`);\n switch (format) {\n case \"json\":\n case \"jsonc\":\n return writeJsonConfig(filePath, key, serverName, serverConfig);\n case \"yaml\":\n return writeYamlConfig(filePath, key, serverName, serverConfig);\n case \"toml\":\n return writeTomlConfig(filePath, key, serverName, serverConfig);\n default:\n throw new Error(`Unsupported config format: ${format as string}`);\n }\n}\n\n/**\n * Remove a server entry from a config file in the specified format.\n *\n * @param filePath - Absolute path to the config file\n * @param format - Config file format\n * @param key - Dot-notation key path to the servers section\n * @param serverName - Name/key of the server entry to remove\n * @returns `true` if the entry was removed, `false` otherwise\n * @throws If the format is unsupported\n *\n * @remarks\n * Delegates to the format-specific removal function. Returns `false` when the\n * file does not exist or the entry is not found.\n *\n * @example\n * ```typescript\n * const removed = await removeConfig(\"/path/to/config.json\", \"jsonc\", \"mcpServers\", \"my-server\");\n * ```\n *\n * @public\n */\nexport async function removeConfig(\n filePath: string,\n format: ConfigFormat,\n key: string,\n serverName: string,\n): Promise<boolean> {\n switch (format) {\n case \"json\":\n case \"jsonc\":\n return removeJsonConfig(filePath, key, serverName);\n case \"yaml\":\n return removeYamlConfig(filePath, key, serverName);\n case \"toml\":\n return removeTomlConfig(filePath, key, serverName);\n default:\n throw new Error(`Unsupported config format: ${format as string}`);\n }\n}\n","/**\n * MCP config reader\n *\n * Reads, lists, and removes MCP server entries from agent config files.\n * Provides the programmatic API that CLI commands delegate to.\n */\n\nimport { existsSync } from \"node:fs\";\nimport type { Provider, McpServerEntry } from \"../../types.js\";\nimport { readConfig, removeConfig } from \"../formats/index.js\";\nimport { getNestedValue } from \"../formats/utils.js\";\nimport { debug } from \"../logger.js\";\nimport { resolveProviderConfigPath, getAgentsMcpServersPath } from \"../paths/standard.js\";\n\n/**\n * Resolve the absolute config file path for a provider and scope.\n *\n * For project scope, joins the project directory with the provider's relative\n * config path. For global scope, returns the provider's global config path.\n *\n * @remarks\n * Delegates to {@link resolveProviderConfigPath} from the paths module.\n * Returns `null` when the provider has no config path defined for the\n * requested scope (e.g. some providers only support global config).\n *\n * @param provider - Provider to resolve config path for\n * @param scope - Whether to resolve project or global config path\n * @param projectDir - Project directory (defaults to `process.cwd()`)\n * @returns Absolute config file path, or `null` if the provider does not support the given scope\n *\n * @example\n * ```typescript\n * const provider = getProvider(\"claude-code\")!;\n * const path = resolveConfigPath(provider, \"project\", \"/home/user/my-project\");\n * // Returns provider-specific project config path\n * ```\n *\n * @public\n */\nexport function resolveConfigPath(\n provider: Provider,\n scope: \"project\" | \"global\",\n projectDir?: string,\n): string | null {\n return resolveProviderConfigPath(provider, scope, projectDir ?? process.cwd());\n}\n\n/**\n * List MCP servers configured for a single provider.\n *\n * Reads the provider's config file, extracts the MCP servers section using the\n * provider's `configKey`, and returns each server entry with metadata.\n *\n * @remarks\n * The config file is read using the format handler matching the provider's\n * `configFormat` (JSON, YAML, or TOML). The `configKey` is used to extract\n * the MCP servers section (e.g. `\"mcpServers\"`, `\"mcp_servers\"`, `\"extensions\"`).\n * Returns an empty array if the file does not exist or cannot be parsed.\n *\n * @param provider - Provider whose config file to read\n * @param scope - Whether to read project or global config\n * @param projectDir - Project directory (defaults to `process.cwd()`)\n * @returns Array of MCP server entries found in the config file\n *\n * @example\n * ```typescript\n * const provider = getProvider(\"claude-code\")!;\n * const servers = await listMcpServers(provider, \"project\", \"/home/user/my-project\");\n * for (const s of servers) {\n * console.log(`${s.name} (${s.scope})`);\n * }\n * ```\n *\n * @public\n */\nexport async function listMcpServers(\n provider: Provider,\n scope: \"project\" | \"global\",\n projectDir?: string,\n): Promise<McpServerEntry[]> {\n const configPath = resolveConfigPath(provider, scope, projectDir);\n debug(`listing MCP servers for ${provider.id} (${scope}) at ${configPath ?? \"(none)\"}`);\n if (!configPath || !existsSync(configPath)) return [];\n\n try {\n const config = await readConfig(configPath, provider.configFormat);\n const servers = getNestedValue(config, provider.configKey);\n\n if (!servers || typeof servers !== \"object\") return [];\n\n const entries: McpServerEntry[] = [];\n for (const [name, cfg] of Object.entries(servers as Record<string, unknown>)) {\n entries.push({\n name,\n providerId: provider.id,\n providerName: provider.toolName,\n scope,\n configPath,\n config: (cfg ?? {}) as Record<string, unknown>,\n });\n }\n\n return entries;\n } catch {\n return [];\n }\n}\n\n/**\n * List MCP servers from the `.agents/mcp/servers.json` standard location.\n *\n * Per the `.agents/` standard (Section 9), this file is the canonical\n * provider-agnostic MCP server registry. It should be checked before\n * per-provider legacy config files.\n *\n * @remarks\n * The `.agents/mcp/servers.json` file uses a `{ \"servers\": { ... } }` structure\n * where each key is a server name. Entries returned from this function use\n * `providerId: \".agents\"` and `providerName: \".agents/ standard\"` to distinguish\n * them from per-provider legacy entries.\n *\n * @param scope - `\"global\"` for `~/.agents/mcp/servers.json`, `\"project\"` for project-level\n * @param projectDir - Project directory (defaults to `process.cwd()`)\n * @returns Array of MCP server entries found in the `.agents/` servers.json\n *\n * @example\n * ```typescript\n * const globalServers = await listAgentsMcpServers(\"global\");\n * const projectServers = await listAgentsMcpServers(\"project\", \"/home/user/my-project\");\n * console.log(`Found ${globalServers.length} global, ${projectServers.length} project servers`);\n * ```\n *\n * @public\n */\nexport async function listAgentsMcpServers(\n scope: \"project\" | \"global\",\n projectDir?: string,\n): Promise<McpServerEntry[]> {\n const serversPath = getAgentsMcpServersPath(scope, projectDir);\n debug(`listing .agents/ MCP servers (${scope}) at ${serversPath}`);\n\n if (!existsSync(serversPath)) return [];\n\n try {\n const config = await readConfig(serversPath, \"json\");\n // .agents/mcp/servers.json uses { \"servers\": { \"<name>\": { ... } } }\n const servers = (config as Record<string, unknown>)[\"servers\"];\n\n if (!servers || typeof servers !== \"object\") return [];\n\n const entries: McpServerEntry[] = [];\n for (const [name, cfg] of Object.entries(servers as Record<string, unknown>)) {\n entries.push({\n name,\n providerId: \".agents\",\n providerName: \".agents/ standard\",\n scope,\n configPath: serversPath,\n config: (cfg ?? {}) as Record<string, unknown>,\n });\n }\n\n return entries;\n } catch {\n return [];\n }\n}\n\n/**\n * List MCP servers across all given providers, deduplicating by config path.\n *\n * Per the `.agents/` standard (Section 9.4), checks `.agents/mcp/servers.json`\n * first, then falls back to per-provider legacy config files. Multiple providers\n * may share the same config file; this function ensures each config file is read\n * only once to avoid duplicate entries.\n *\n * @remarks\n * The deduplication is path-based: if two providers share the same config file\n * (resolved to the same absolute path), it is read only once. The `.agents/`\n * standard location is always checked first and takes precedence.\n *\n * @param providers - Array of providers to query\n * @param scope - Whether to read project or global config\n * @param projectDir - Project directory (defaults to `process.cwd()`)\n * @returns Combined array of MCP server entries from all providers\n *\n * @example\n * ```typescript\n * const installed = getInstalledProviders();\n * const allServers = await listAllMcpServers(installed, \"global\", \"/home/user/my-project\");\n * console.log(`Found ${allServers.length} servers across all providers`);\n * ```\n *\n * @public\n */\nexport async function listAllMcpServers(\n providers: Provider[],\n scope: \"project\" | \"global\",\n projectDir?: string,\n): Promise<McpServerEntry[]> {\n const seen = new Set<string>();\n const allEntries: McpServerEntry[] = [];\n\n // Check .agents/mcp/servers.json first (standard takes precedence)\n const agentsServersPath = getAgentsMcpServersPath(scope, projectDir);\n const agentsEntries = await listAgentsMcpServers(scope, projectDir);\n if (agentsEntries.length > 0) {\n allEntries.push(...agentsEntries);\n seen.add(agentsServersPath);\n }\n\n // Then check per-provider legacy config files\n for (const provider of providers) {\n const configPath = resolveConfigPath(provider, scope, projectDir);\n if (!configPath || seen.has(configPath)) continue;\n seen.add(configPath);\n\n const entries = await listMcpServers(provider, scope, projectDir);\n allEntries.push(...entries);\n }\n\n return allEntries;\n}\n\n/**\n * Remove an MCP server entry from a provider's config file.\n *\n * @remarks\n * Delegates to the format-specific `removeConfig` handler. If the provider\n * does not have a config path for the requested scope, returns `false`\n * without modifying any files.\n *\n * @param provider - Provider whose config file to modify\n * @param serverName - Name/key of the MCP server to remove\n * @param scope - Whether to modify project or global config\n * @param projectDir - Project directory (defaults to `process.cwd()`)\n * @returns `true` if the entry was removed, `false` if no config path exists\n *\n * @example\n * ```typescript\n * const provider = getProvider(\"claude-code\")!;\n * const removed = await removeMcpServer(provider, \"my-server\", \"project\", \"/home/user/my-project\");\n * ```\n *\n * @public\n */\nexport async function removeMcpServer(\n provider: Provider,\n serverName: string,\n scope: \"project\" | \"global\",\n projectDir?: string,\n): Promise<boolean> {\n const configPath = resolveConfigPath(provider, scope, projectDir);\n if (!configPath) return false;\n\n return removeConfig(configPath, provider.configFormat, provider.configKey, serverName);\n}\n","/**\n * Per-agent MCP config transformations\n *\n * Most agents use the canonical McpServerConfig directly.\n * These transforms handle agents with non-standard schemas.\n */\n\nimport type { McpServerConfig } from \"../../types.js\";\n\n/**\n * Transform a canonical MCP server config into the Goose YAML extensions format.\n *\n * @remarks\n * Goose uses a YAML-based extensions format with `name`, `type`, and `uri`/`cmd` fields\n * instead of the standard `mcpServers` JSON structure. Remote servers use `sse` or\n * `streamable_http` transport types, while stdio servers use `type: \"stdio\"` with\n * `cmd` and `args` fields. Environment variables are mapped to `envs`.\n *\n * @param serverName - Display name for the server in Goose config\n * @param config - Canonical MCP server configuration to transform\n * @returns Goose-formatted server configuration object\n *\n * @example\n * ```typescript\n * const gooseConfig = transformGoose(\"filesystem\", {\n * command: \"npx\",\n * args: [\"-y\", \"@modelcontextprotocol/server-filesystem\"],\n * });\n * // { name: \"filesystem\", type: \"stdio\", cmd: \"npx\", args: [...], enabled: true, timeout: 300 }\n * ```\n *\n * @public\n */\nexport function transformGoose(serverName: string, config: McpServerConfig): unknown {\n if (config.url) {\n // Remote server\n const transport = config.type === \"sse\" ? \"sse\" : \"streamable_http\";\n return {\n name: serverName,\n type: transport,\n uri: config.url,\n ...(config.headers ? { headers: config.headers } : {}),\n enabled: true,\n timeout: 300,\n };\n }\n\n // Stdio server\n return {\n name: serverName,\n type: \"stdio\",\n cmd: config.command,\n args: config.args ?? [],\n ...(config.env ? { envs: config.env } : {}),\n enabled: true,\n timeout: 300,\n };\n}\n\n/**\n * Transform a canonical MCP server config into the Zed context_servers format.\n *\n * @remarks\n * Zed uses a `context_servers` key with `source: \"custom\"` and either a `url` for\n * remote servers or `command`/`args` for stdio servers. The server name is not included\n * in the config body since it is used as the object key in the parent map.\n *\n * @param _serverName - Server name (unused, Zed uses it as the object key externally)\n * @param config - Canonical MCP server configuration to transform\n * @returns Zed-formatted server configuration object\n *\n * @example\n * ```typescript\n * const zedConfig = transformZed(\"filesystem\", {\n * command: \"npx\",\n * args: [\"-y\", \"@modelcontextprotocol/server-filesystem\"],\n * });\n * // { source: \"custom\", command: \"npx\", args: [...] }\n * ```\n *\n * @public\n */\nexport function transformZed(_serverName: string, config: McpServerConfig): unknown {\n if (config.url) {\n return {\n source: \"custom\",\n type: config.type ?? \"http\",\n url: config.url,\n ...(config.headers ? { headers: config.headers } : {}),\n };\n }\n\n return {\n source: \"custom\",\n command: config.command,\n args: config.args ?? [],\n ...(config.env ? { env: config.env } : {}),\n };\n}\n\n/**\n * Transform a canonical MCP server config into the OpenCode mcp format.\n *\n * @remarks\n * OpenCode uses a flat `mcp` key with `type: \"local\"` or `type: \"remote\"`. Local servers\n * combine `command` and `args` into a single `command` array. Environment variables are\n * mapped to the `environment` field instead of `env`.\n *\n * @param _serverName - Server name (unused, OpenCode uses it as the object key externally)\n * @param config - Canonical MCP server configuration to transform\n * @returns OpenCode-formatted server configuration object\n *\n * @example\n * ```typescript\n * const openCodeConfig = transformOpenCode(\"filesystem\", {\n * command: \"npx\",\n * args: [\"-y\", \"@modelcontextprotocol/server-filesystem\"],\n * });\n * // { type: \"local\", command: [\"npx\", \"-y\", \"@modelcontextprotocol/server-filesystem\"], enabled: true }\n * ```\n *\n * @public\n */\nexport function transformOpenCode(_serverName: string, config: McpServerConfig): unknown {\n if (config.url) {\n return {\n type: \"remote\",\n url: config.url,\n enabled: true,\n ...(config.headers ? { headers: config.headers } : {}),\n };\n }\n\n return {\n type: \"local\",\n command: [config.command, ...(config.args ?? [])],\n enabled: true,\n ...(config.env ? { environment: config.env } : {}),\n };\n}\n\n/**\n * Transform a canonical MCP server config into the Codex TOML mcp_servers format.\n *\n * @remarks\n * Codex uses a TOML-based `mcp_servers` key. Remote servers include `type` and `url`,\n * while stdio servers use `command`/`args`/`env` fields without a `type` discriminator.\n *\n * @param _serverName - Server name (unused, Codex uses it as the TOML table key externally)\n * @param config - Canonical MCP server configuration to transform\n * @returns Codex-formatted server configuration object\n *\n * @example\n * ```typescript\n * const codexConfig = transformCodex(\"filesystem\", {\n * command: \"npx\",\n * args: [\"-y\", \"@modelcontextprotocol/server-filesystem\"],\n * });\n * // { command: \"npx\", args: [\"-y\", \"@modelcontextprotocol/server-filesystem\"] }\n * ```\n *\n * @public\n */\nexport function transformCodex(_serverName: string, config: McpServerConfig): unknown {\n if (config.url) {\n return {\n type: config.type ?? \"http\",\n url: config.url,\n ...(config.headers ? { headers: config.headers } : {}),\n };\n }\n\n return {\n command: config.command,\n args: config.args ?? [],\n ...(config.env ? { env: config.env } : {}),\n };\n}\n\n/**\n * Transform a canonical MCP server config into the Cursor mcpServers format.\n *\n * @remarks\n * Cursor uses the standard `mcpServers` key but strips the `type` field from remote\n * server configs, keeping only `url` and optional `headers`. Stdio configs pass\n * through unchanged since they already match the expected format.\n *\n * @param _serverName - Server name (unused, Cursor uses it as the object key externally)\n * @param config - Canonical MCP server configuration to transform\n * @returns Cursor-formatted server configuration object\n *\n * @example\n * ```typescript\n * const cursorConfig = transformCursor(\"remote-server\", {\n * type: \"http\",\n * url: \"https://mcp.example.com\",\n * });\n * // { url: \"https://mcp.example.com\" }\n * ```\n *\n * @public\n */\nexport function transformCursor(_serverName: string, config: McpServerConfig): unknown {\n if (config.url) {\n return {\n url: config.url,\n ...(config.headers ? { headers: config.headers } : {}),\n };\n }\n\n // Stdio passthrough\n return config;\n}\n\n/**\n * Get the config transform function for a provider, or `undefined` for passthrough.\n *\n * Providers with non-standard MCP config schemas (Goose, Zed, OpenCode, Codex, Cursor)\n * require transforms to convert the canonical {@link McpServerConfig} into their\n * provider-specific format.\n *\n * @remarks\n * Five of the 28+ supported providers use non-standard MCP config schemas.\n * This function acts as a registry of transform functions, returning `undefined`\n * for providers that accept the canonical format directly (the majority).\n * The returned function takes a server name and canonical config and produces\n * the provider-specific shape.\n *\n * @param providerId - Provider ID to look up (e.g. `\"goose\"`, `\"zed\"`)\n * @returns Transform function, or `undefined` if the provider uses the canonical format\n *\n * @example\n * ```typescript\n * const transform = getTransform(\"goose\");\n * if (transform) {\n * const gooseConfig = transform(\"my-server\", { command: \"npx\", args: [\"-y\", \"@mcp/server\"] });\n * }\n * ```\n *\n * @see {@link transformGoose}\n * @see {@link transformZed}\n *\n * @public\n */\nexport function getTransform(\n providerId: string,\n): ((name: string, config: McpServerConfig) => unknown) | undefined {\n switch (providerId) {\n case \"goose\":\n return transformGoose;\n case \"zed\":\n return transformZed;\n case \"opencode\":\n return transformOpenCode;\n case \"codex\":\n return transformCodex;\n case \"cursor\":\n return transformCursor;\n default:\n return undefined;\n }\n}\n","/**\n * MCP config installer\n *\n * Writes MCP server configurations to agent config files,\n * handling per-agent formats, keys, and transformations.\n */\n\nimport type { McpServerConfig, Provider, } from \"../../types.js\";\nimport { writeConfig } from \"../formats/index.js\";\nimport { debug } from \"../logger.js\";\nimport { resolveConfigPath } from \"./reader.js\";\nimport { getTransform } from \"./transforms.js\";\n\n/**\n * Result of installing an MCP server configuration to a single provider.\n *\n * @example\n * ```typescript\n * const provider = getProvider(\"claude-code\")!;\n * const result = await installMcpServer(provider, \"my-server\", {\n * command: \"npx\",\n * args: [\"-y\", \"@modelcontextprotocol/server-filesystem\"],\n * });\n * if (result.success) {\n * console.log(`Written to ${result.configPath}`);\n * }\n * ```\n *\n * @public\n */\nexport interface InstallResult {\n /** The provider the config was written to. */\n provider: Provider;\n /** Whether project or global scope was used. */\n scope: \"project\" | \"global\";\n /** Absolute path to the config file that was written. */\n configPath: string;\n /** Whether the write succeeded. */\n success: boolean;\n /** Error message if the write failed. @defaultValue undefined */\n error?: string;\n}\n\n/** Build the config to write, applying transforms if needed */\nfunction buildConfig(provider: Provider, serverName: string, config: McpServerConfig): unknown {\n const transform = getTransform(provider.id);\n if (transform) {\n return transform(serverName, config);\n }\n return config;\n}\n\n/**\n * Install an MCP server configuration for a single provider.\n *\n * Applies provider-specific transforms (e.g. Goose, Zed, Codex) and writes\n * the config to the provider's config file in the specified scope.\n *\n * @remarks\n * The installation flow is: resolve config path, apply any provider-specific\n * transform via {@link getTransform}, then write the result using the\n * provider's config format (JSON, YAML, or TOML). If the provider does not\n * support the requested scope, a failed result is returned without throwing.\n *\n * @param provider - Target provider to write config for\n * @param serverName - Name/key for the MCP server entry\n * @param config - Canonical MCP server configuration\n * @param scope - Whether to write to project or global config (default: `\"project\"`)\n * @param projectDir - Project directory path (defaults to `process.cwd()`)\n * @returns Install result with success status and config path\n *\n * @example\n * ```typescript\n * const provider = getProvider(\"claude-code\")!;\n * const result = await installMcpServer(provider, \"filesystem\", {\n * command: \"npx\",\n * args: [\"-y\", \"@modelcontextprotocol/server-filesystem\"],\n * }, \"project\", \"/home/user/my-project\");\n * ```\n *\n * @public\n */\nexport async function installMcpServer(\n provider: Provider,\n serverName: string,\n config: McpServerConfig,\n scope: \"project\" | \"global\" = \"project\",\n projectDir?: string,\n): Promise<InstallResult> {\n const configPath = resolveConfigPath(provider, scope, projectDir);\n\n debug(`installing MCP server \"${serverName}\" for ${provider.id} (${scope})`);\n debug(` config path: ${configPath ?? \"(none)\"}`);\n\n if (!configPath) {\n return {\n provider,\n scope,\n configPath: \"\",\n success: false,\n error: `Provider ${provider.id} does not support ${scope} config`,\n };\n }\n\n try {\n const transformedConfig = buildConfig(provider, serverName, config);\n const transform = getTransform(provider.id);\n debug(` transform applied: ${transform ? \"yes\" : \"no\"}`);\n\n await writeConfig(\n configPath,\n provider.configFormat,\n provider.configKey,\n serverName,\n transformedConfig,\n );\n\n return {\n provider,\n scope,\n configPath,\n success: true,\n };\n } catch (err) {\n return {\n provider,\n scope,\n configPath,\n success: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n}\n\n/**\n * Install an MCP server configuration to multiple providers.\n *\n * Calls {@link installMcpServer} for each provider sequentially and collects results.\n *\n * @remarks\n * Providers are processed sequentially (not in parallel) to avoid concurrent\n * writes to shared config files. Each provider's result is independent --\n * a failure for one provider does not prevent installation to others.\n *\n * @param providers - Array of target providers\n * @param serverName - Name/key for the MCP server entry\n * @param config - Canonical MCP server configuration\n * @param scope - Whether to write to project or global config (default: `\"project\"`)\n * @param projectDir - Project directory path (defaults to `process.cwd()`)\n * @returns Array of install results, one per provider\n *\n * @example\n * ```typescript\n * const providers = getInstalledProviders();\n * const config = { command: \"npx\", args: [\"-y\", \"@mcp/server\"] };\n * const results = await installMcpServerToAll(providers, \"my-server\", config, \"project\", \"/home/user/project\");\n * const successes = results.filter(r => r.success);\n * ```\n *\n * @see {@link installMcpServer}\n *\n * @public\n */\nexport async function installMcpServerToAll(\n providers: Provider[],\n serverName: string,\n config: McpServerConfig,\n scope: \"project\" | \"global\" = \"project\",\n projectDir?: string,\n): Promise<InstallResult[]> {\n const results: InstallResult[] = [];\n\n for (const provider of providers) {\n const result = await installMcpServer(provider, serverName, config, scope, projectDir);\n results.push(result);\n }\n\n return results;\n}\n\n/**\n * Build a canonical {@link McpServerConfig} from a parsed source.\n *\n * Maps source types to appropriate transport configurations:\n * - `\"remote\"` sources become HTTP/SSE configs with a `url`\n * - `\"package\"` sources become `npx -y <package>` stdio configs\n * - All others are treated as shell commands split into `command` + `args`\n *\n * @remarks\n * This function normalizes diverse source inputs into the canonical config\n * format that CAAMP uses internally. Provider-specific transforms are applied\n * later during installation via {@link getTransform}. Command-type sources\n * are split on whitespace, with the first token becoming `command` and the\n * remainder becoming `args`.\n *\n * @param source - Parsed source with `type` and `value`\n * @param transport - Override transport type for remote sources (default: `\"http\"`)\n * @param headers - Optional HTTP headers for remote servers\n * @returns Canonical MCP server configuration\n *\n * @example\n * ```typescript\n * buildServerConfig({ type: \"package\", value: \"@mcp/server-fs\" }, undefined, undefined);\n * // { command: \"npx\", args: [\"-y\", \"@mcp/server-fs\"] }\n *\n * buildServerConfig({ type: \"remote\", value: \"https://mcp.example.com\" }, \"http\", { \"Authorization\": \"Bearer token\" });\n * // { type: \"http\", url: \"https://mcp.example.com\", headers: { \"Authorization\": \"Bearer token\" } }\n * ```\n *\n * @see {@link installMcpServer}\n *\n * @public\n */\nexport function buildServerConfig(\n source: { type: string; value: string },\n transport?: string,\n headers?: Record<string, string>,\n): McpServerConfig {\n if (source.type === \"remote\") {\n return {\n type: (transport ?? \"http\") as \"sse\" | \"http\",\n url: source.value,\n ...(headers && Object.keys(headers).length > 0 ? { headers } : {}),\n };\n }\n\n if (source.type === \"package\") {\n return {\n command: \"npx\",\n args: [\"-y\", source.value],\n };\n }\n\n // Command type - split into command and args\n const parts = source.value.trim().split(/\\s+/);\n const command = parts[0] ?? source.value;\n return {\n command,\n args: parts.slice(1),\n };\n}\n","/**\n * Provider auto-detection engine\n *\n * Detects which AI coding agents are installed on the system\n * by checking binaries, directories, app bundles, and flatpak.\n */\n\nimport { execFileSync } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { Provider } from \"../../types.js\";\nimport { debug } from \"../logger.js\";\nimport { getPlatformLocations, resolveProviderProjectPath } from \"../paths/standard.js\";\nimport { getAllProviders } from \"./providers.js\";\n\n/**\n * Result of detecting whether a provider is installed on the system.\n *\n * @example\n * ```typescript\n * const provider = getProvider(\"claude-code\")!;\n * const result = detectProvider(provider);\n * if (result.installed) {\n * console.log(`Found via: ${result.methods.join(\", \")}`);\n * }\n * ```\n *\n * @public\n */\nexport interface DetectionResult {\n /** The provider that was checked. */\n provider: Provider;\n /** Whether the provider was detected as installed. */\n installed: boolean;\n /** Detection methods that matched (e.g. `[\"binary\", \"directory\"]`). */\n methods: string[];\n /** Whether the provider has project-level config in the current directory. */\n projectDetected: boolean;\n}\n\n/**\n * Options for controlling the detection result cache.\n *\n * @public\n */\nexport interface DetectionCacheOptions {\n /** Whether to bypass the cache and force a fresh detection scan. @defaultValue false */\n forceRefresh?: boolean;\n /** Time-to-live for cached results in milliseconds. @defaultValue 30000 */\n ttlMs?: number;\n}\n\ninterface DetectionCacheState {\n createdAt: number;\n signature: string;\n results: DetectionResult[];\n}\n\nconst DEFAULT_DETECTION_CACHE_TTL_MS = 30_000;\nlet detectionCache: DetectionCacheState | null = null;\n\nfunction checkBinary(binary: string): boolean {\n try {\n const cmd = process.platform === \"win32\" ? \"where\" : \"which\";\n execFileSync(cmd, [binary], { stdio: \"pipe\" });\n return true;\n } catch {\n return false;\n }\n}\n\nfunction checkDirectory(dir: string): boolean {\n return existsSync(dir);\n}\n\nfunction checkAppBundle(appName: string): boolean {\n if (process.platform !== \"darwin\") return false;\n const applications = getPlatformLocations().applications;\n return applications.some((base) => existsSync(join(base, appName)));\n}\n\nfunction checkFlatpak(flatpakId: string): boolean {\n if (process.platform !== \"linux\") return false;\n try {\n execFileSync(\"flatpak\", [\"info\", flatpakId], { stdio: \"pipe\" });\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Detect if a single provider is installed on the system.\n *\n * Checks each detection method configured for the provider (binary, directory,\n * appBundle, flatpak) and returns which methods matched.\n *\n * @remarks\n * Detection methods are defined per-provider in `providers/registry.json`.\n * Each method is checked in order: `binary` uses `which`/`where` to find\n * executables, `directory` checks for config directories, `appBundle` looks\n * in macOS Applications folders, and `flatpak` queries flatpak on Linux.\n * The `projectDetected` field is always `false` here; use\n * {@link detectProjectProviders} for project-level detection.\n *\n * @param provider - The provider to detect\n * @returns Detection result with installation status and matched methods\n *\n * @example\n * ```typescript\n * const provider = getProvider(\"claude-code\")!;\n * const result = detectProvider(provider);\n * if (result.installed) {\n * console.log(`Claude Code found via: ${result.methods.join(\", \")}`);\n * }\n * ```\n *\n * @public\n */\nexport function detectProvider(provider: Provider): DetectionResult {\n const matchedMethods: string[] = [];\n const detection = provider.detection;\n\n debug(`detecting provider ${provider.id} via methods: ${detection.methods.join(\", \")}`);\n\n for (const method of detection.methods) {\n switch (method) {\n case \"binary\":\n if (detection.binary && checkBinary(detection.binary)) {\n debug(` ${provider.id}: binary \"${detection.binary}\" found`);\n matchedMethods.push(\"binary\");\n }\n break;\n case \"directory\":\n if (detection.directories) {\n for (const dir of detection.directories) {\n if (checkDirectory(dir)) {\n matchedMethods.push(\"directory\");\n break;\n }\n }\n }\n break;\n case \"appBundle\":\n if (detection.appBundle && checkAppBundle(detection.appBundle)) {\n matchedMethods.push(\"appBundle\");\n }\n break;\n case \"flatpak\":\n if (detection.flatpakId && checkFlatpak(detection.flatpakId)) {\n matchedMethods.push(\"flatpak\");\n }\n break;\n }\n }\n\n return {\n provider,\n installed: matchedMethods.length > 0,\n methods: matchedMethods,\n projectDetected: false,\n };\n}\n\nfunction providerSignature(provider: Provider): string {\n return JSON.stringify({\n id: provider.id,\n methods: provider.detection.methods,\n binary: provider.detection.binary,\n directories: provider.detection.directories,\n appBundle: provider.detection.appBundle,\n flatpakId: provider.detection.flatpakId,\n });\n}\n\nfunction buildProvidersSignature(providers: Provider[]): string {\n if (!providers || !Array.isArray(providers)) return \"\";\n return providers.map(providerSignature).join(\"|\");\n}\n\nfunction cloneDetectionResults(results: DetectionResult[]): DetectionResult[] {\n return results.map((result) => ({\n provider: result.provider,\n installed: result.installed,\n methods: [...result.methods],\n projectDetected: result.projectDetected,\n }));\n}\n\nfunction getCachedResults(\n signature: string,\n options: DetectionCacheOptions,\n): DetectionResult[] | null {\n if (!detectionCache || options.forceRefresh) return null;\n if (detectionCache.signature !== signature) return null;\n\n const ttlMs = options.ttlMs ?? DEFAULT_DETECTION_CACHE_TTL_MS;\n if (ttlMs <= 0) return null;\n if ((Date.now() - detectionCache.createdAt) > ttlMs) return null;\n\n return cloneDetectionResults(detectionCache.results);\n}\n\nfunction setCachedResults(signature: string, results: DetectionResult[]): void {\n detectionCache = {\n createdAt: Date.now(),\n signature,\n results: cloneDetectionResults(results),\n };\n}\n\n/**\n * Detect if a provider has project-level config in the given directory.\n *\n * @remarks\n * Checks whether the provider's `pathProject` config file exists within the\n * given project directory. Returns `false` if the provider has no project-level\n * path defined.\n *\n * @param provider - Provider to check for project-level config\n * @param projectDir - Absolute path to the project directory\n * @returns `true` if the provider has a config file in the project directory\n *\n * @example\n * ```typescript\n * const provider = getProvider(\"claude-code\")!;\n * const hasProjectConfig = detectProjectProvider(provider, \"/home/user/my-project\");\n * ```\n *\n * @public\n */\nexport function detectProjectProvider(provider: Provider, projectDir: string): boolean {\n if (!provider.pathProject) return false;\n return existsSync(resolveProviderProjectPath(provider, projectDir));\n}\n\n/**\n * Detect all registered providers and return their installation status.\n *\n * Runs detection for every provider in the registry.\n *\n * @remarks\n * Results are cached in memory with a configurable TTL (default 30 seconds).\n * The cache key is a signature of all provider detection configurations, so\n * it auto-invalidates if the registry changes. Pass `{ forceRefresh: true }`\n * to bypass the cache.\n *\n * @param options - Cache control options\n * @returns Array of detection results for all providers\n *\n * @example\n * ```typescript\n * const results = detectAllProviders({ forceRefresh: true });\n * const installed = results.filter(r => r.installed);\n * console.log(`${installed.length} agents detected`);\n * ```\n *\n * @public\n */\nexport function detectAllProviders(options: DetectionCacheOptions = {}): DetectionResult[] {\n const providers = getAllProviders() ?? [];\n const signature = buildProvidersSignature(providers);\n const cached = getCachedResults(signature, options);\n if (cached) {\n debug(`detection cache hit for ${providers.length} providers`);\n return cached;\n }\n\n const results = providers.map(detectProvider);\n setCachedResults(signature, results);\n return cloneDetectionResults(results);\n}\n\n/**\n * Get only providers that are currently installed on the system.\n *\n * Convenience wrapper that filters {@link detectAllProviders} results to only\n * those with `installed === true`.\n *\n * @remarks\n * Delegates to {@link detectAllProviders} and extracts the `provider` object\n * from each result where `installed` is true. Cache behavior is inherited\n * from the underlying detection call.\n *\n * @param options - Cache control options passed through to detection\n * @returns Array of installed provider definitions\n *\n * @example\n * ```typescript\n * const installed = getInstalledProviders({ forceRefresh: true });\n * console.log(installed.map(p => p.toolName).join(\", \"));\n * ```\n *\n * @see {@link detectAllProviders}\n *\n * @public\n */\nexport function getInstalledProviders(options: DetectionCacheOptions = {}): Provider[] {\n return detectAllProviders(options)\n .filter((r) => r.installed)\n .map((r) => r.provider);\n}\n\n/**\n * Detect all providers and enrich results with project-level presence.\n *\n * Extends {@link detectAllProviders} by also checking whether each provider\n * has a project-level config file in the given directory.\n *\n * @remarks\n * Calls {@link detectAllProviders} for system-level detection, then overlays\n * project-level checks via {@link detectProjectProvider} for each result.\n * The `projectDetected` field in the returned results will be `true` when the\n * provider has a config file (e.g. `.claude/settings.json`) in the given directory.\n *\n * @param projectDir - Absolute path to the project directory to check\n * @param options - Cache control options passed through to detection\n * @returns Array of detection results with `projectDetected` populated\n *\n * @example\n * ```typescript\n * const results = detectProjectProviders(\"/home/user/my-project\", { forceRefresh: true });\n * for (const r of results) {\n * if (r.projectDetected) {\n * console.log(`${r.provider.toolName} has project config`);\n * }\n * }\n * ```\n *\n * @see {@link detectAllProviders}\n *\n * @public\n */\nexport function detectProjectProviders(projectDir: string, options: DetectionCacheOptions = {}): DetectionResult[] {\n const results = detectAllProviders(options);\n return results.map((r) => ({\n ...r,\n projectDetected: detectProjectProvider(r.provider, projectDir),\n }));\n}\n\n/**\n * Reset the detection result cache, forcing fresh detection on next call.\n *\n * @remarks\n * Clears the in-memory detection cache. Primarily used in test suites to\n * ensure deterministic results between test cases. After calling this,\n * the next invocation of {@link detectAllProviders} will perform a full\n * system scan regardless of TTL.\n *\n * @example\n * ```typescript\n * resetDetectionCache();\n * // Next detectAllProviders() call will bypass cache\n * const fresh = detectAllProviders();\n * ```\n *\n * @public\n */\nexport function resetDetectionCache(): void {\n detectionCache = null;\n}\n","/**\n * Skill installer - canonical + symlink model\n *\n * Skills are stored once in a canonical location (.agents/skills/<name>/)\n * and symlinked to each target agent's skills directory.\n */\n\nimport { existsSync, lstatSync } from \"node:fs\";\nimport { cp, mkdir, rm, symlink } from \"node:fs/promises\";\nimport { join, relative, resolve } from \"node:path\";\nimport type { ParsedSource, Provider, SkillMetadata } from \"../../types.js\";\nimport { getCanonicalSkillsDir, resolveProviderSkillsDirs } from \"../paths/standard.js\";\nimport { discoverSkill } from \"./discovery.js\";\n\n/**\n * Result of installing a skill to the canonical location and linking to agents.\n *\n * @example\n * ```typescript\n * const result = await installSkill(sourcePath, \"my-skill\", providers, true);\n * if (result.success) {\n * console.log(`Installed to ${result.canonicalPath}`);\n * console.log(`Linked to: ${result.linkedAgents.join(\", \")}`);\n * }\n * ```\n *\n * @public\n */\nexport interface SkillInstallResult {\n /** Skill name. */\n name: string;\n /** Absolute path to the canonical installation directory. */\n canonicalPath: string;\n /** Provider IDs that were successfully linked. */\n linkedAgents: string[];\n /** Error messages from failed link operations. */\n errors: string[];\n /** Whether at least one agent was successfully linked. */\n success: boolean;\n}\n\n/** Ensure canonical skills directory exists */\nasync function ensureCanonicalDir(): Promise<void> {\n await mkdir(getCanonicalSkillsDir(), { recursive: true });\n}\n\n/**\n * Copy skill files to the canonical location.\n *\n * @remarks\n * Removes any existing installation at the target directory before copying.\n * Handles race conditions where another concurrent install may create the\n * directory between removal and copy by retrying the operation.\n *\n * @param sourcePath - Absolute path to the source skill directory to copy\n * @param skillName - Name for the skill (used as the subdirectory name)\n * @returns Absolute path to the canonical installation directory\n *\n * @example\n * ```typescript\n * const canonicalPath = await installToCanonical(\"/tmp/my-skill\", \"my-skill\");\n * console.log(`Installed to: ${canonicalPath}`);\n * ```\n *\n * @public\n */\nexport async function installToCanonical(\n sourcePath: string,\n skillName: string,\n): Promise<string> {\n await ensureCanonicalDir();\n\n const targetDir = join(getCanonicalSkillsDir(), skillName);\n\n // Remove existing (force: true ignores ENOENT if it doesn't exist)\n await rm(targetDir, { recursive: true, force: true });\n\n try {\n await cp(sourcePath, targetDir, { recursive: true });\n } catch (err: unknown) {\n // Handle race condition: another concurrent install may have created the dir\n if (err && typeof err === \"object\" && \"code\" in err && err.code === \"EEXIST\") {\n await rm(targetDir, { recursive: true, force: true });\n await cp(sourcePath, targetDir, { recursive: true });\n } else {\n throw err;\n }\n }\n\n return targetDir;\n}\n\n/** Create symlinks from an agent's skills directories to the canonical location */\nasync function linkToAgent(\n canonicalPath: string,\n provider: Provider,\n skillName: string,\n isGlobal: boolean,\n projectDir?: string,\n): Promise<{ success: boolean; error?: string }> {\n const scope = isGlobal ? \"global\" : \"project\";\n const targetDirs = resolveProviderSkillsDirs(provider, scope, projectDir);\n\n if (targetDirs.length === 0) {\n return { success: false, error: `Provider ${provider.id} has no skills directory` };\n }\n\n const errors: string[] = [];\n let anySuccess = false;\n\n for (const targetSkillsDir of targetDirs) {\n if (!targetSkillsDir) continue;\n\n try {\n await mkdir(targetSkillsDir, { recursive: true });\n\n const linkPath = join(targetSkillsDir, skillName);\n\n // Remove existing link/directory\n if (existsSync(linkPath)) {\n const stat = lstatSync(linkPath);\n if (stat.isSymbolicLink()) {\n await rm(linkPath);\n } else {\n await rm(linkPath, { recursive: true });\n }\n }\n\n // Create symlink (junction on Windows for compat)\n const symlinkType = process.platform === \"win32\" ? \"junction\" : \"dir\";\n try {\n await symlink(canonicalPath, linkPath, symlinkType);\n } catch {\n // Fallback to copy if symlinks not supported\n await cp(canonicalPath, linkPath, { recursive: true });\n }\n\n anySuccess = true;\n } catch (err) {\n errors.push(err instanceof Error ? err.message : String(err));\n }\n }\n\n if (anySuccess) {\n return { success: true };\n }\n return {\n success: false,\n error: errors.join(\"; \") || `Provider ${provider.id} has no skills directory`,\n };\n}\n\n/**\n * Install a skill from a local path to the canonical location and link to agents.\n *\n * @remarks\n * Copies the skill directory to the canonical skills directory and creates symlinks\n * (or copies on Windows) from each provider's skills directory to the canonical path.\n *\n * @param sourcePath - Local path to the skill directory to install\n * @param skillName - Name for the installed skill\n * @param providers - Target providers to link the skill to\n * @param isGlobal - Whether to link to global or project skill directories\n * @param projectDir - Project directory (defaults to `process.cwd()`)\n * @returns Install result with linked agents and any errors\n *\n * @example\n * ```typescript\n * const result = await installSkill(\"/tmp/my-skill\", \"my-skill\", providers, true, \"/my/project\");\n * if (result.success) {\n * console.log(`Linked to: ${result.linkedAgents.join(\", \")}`);\n * }\n * ```\n *\n * @public\n */\nexport async function installSkill(\n sourcePath: string,\n skillName: string,\n providers: Provider[],\n isGlobal: boolean,\n projectDir?: string,\n): Promise<SkillInstallResult> {\n const errors: string[] = [];\n const linkedAgents: string[] = [];\n\n // Step 1: Install to canonical location\n const canonicalPath = await installToCanonical(sourcePath, skillName);\n\n // Step 2: Link to each agent\n for (const provider of providers) {\n const result = await linkToAgent(canonicalPath, provider, skillName, isGlobal, projectDir);\n if (result.success) {\n linkedAgents.push(provider.id);\n } else if (result.error) {\n errors.push(`${provider.id}: ${result.error}`);\n }\n }\n\n return {\n name: skillName,\n canonicalPath,\n linkedAgents,\n errors,\n success: linkedAgents.length > 0,\n };\n}\n\n/**\n * Remove a skill from the canonical location and all agent symlinks.\n *\n * @remarks\n * Removes symlinks from each provider's skills directory and then removes the\n * canonical copy from the centralized canonical skills directory.\n *\n * @param skillName - Name of the skill to remove\n * @param providers - Providers to unlink the skill from\n * @param isGlobal - Whether to target global or project skill directories\n * @param projectDir - Project directory (defaults to `process.cwd()`)\n * @returns Object with arrays of successfully removed provider IDs and error messages\n *\n * @example\n * ```typescript\n * const { removed, errors } = await removeSkill(\"my-skill\", providers, true, \"/my/project\");\n * console.log(`Removed from: ${removed.join(\", \")}`);\n * ```\n *\n * @public\n */\nexport async function removeSkill(\n skillName: string,\n providers: Provider[],\n isGlobal: boolean,\n projectDir?: string,\n): Promise<{ removed: string[]; errors: string[] }> {\n const removed: string[] = [];\n const errors: string[] = [];\n\n // Remove symlinks from each agent (all precedence-aware paths)\n for (const provider of providers) {\n const scope = isGlobal ? \"global\" : \"project\";\n const targetDirs = resolveProviderSkillsDirs(provider, scope, projectDir);\n let providerRemoved = false;\n\n for (const skillsDir of targetDirs) {\n if (!skillsDir) continue;\n\n const linkPath = join(skillsDir, skillName);\n if (existsSync(linkPath)) {\n try {\n await rm(linkPath, { recursive: true });\n providerRemoved = true;\n } catch (err) {\n errors.push(`${provider.id}: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n }\n\n if (providerRemoved) {\n removed.push(provider.id);\n }\n }\n\n // Remove canonical copy\n const canonicalPath = join(getCanonicalSkillsDir(), skillName);\n if (existsSync(canonicalPath)) {\n try {\n await rm(canonicalPath, { recursive: true });\n } catch (err) {\n errors.push(`canonical: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n return { removed, errors };\n}\n\n/**\n * List all skills installed in the canonical skills directory.\n *\n * @remarks\n * Returns the directory names of all skills, which correspond to skill names.\n * Includes both regular directories and symlinks in the canonical location.\n *\n * @returns Array of skill names\n *\n * @example\n * ```typescript\n * const skills = await listCanonicalSkills();\n * // [\"my-skill\", \"another-skill\"]\n * ```\n *\n * @public\n */\nexport async function listCanonicalSkills(): Promise<string[]> {\n if (!existsSync(getCanonicalSkillsDir())) return [];\n\n const { readdir } = await import(\"node:fs/promises\");\n const entries = await readdir(getCanonicalSkillsDir(), { withFileTypes: true });\n return entries\n .filter((e) => e.isDirectory() || e.isSymbolicLink())\n .map((e) => e.name);\n}\n","/**\n * Advanced orchestration helpers for multi-provider operations.\n *\n * These helpers compose CAAMP's lower-level APIs into production patterns:\n * tier-based targeting, conflict-aware installs, and rollback-capable batches.\n */\n\nimport { existsSync, lstatSync } from \"node:fs\";\nimport {\n cp,\n mkdir,\n readFile,\n readlink,\n rm,\n symlink,\n writeFile,\n} from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { basename, dirname, join } from \"node:path\";\nimport type {\n ConfigFormat,\n McpServerConfig,\n Provider,\n ProviderPriority,\n} from \"../../types.js\";\nimport { injectAll } from \"../instructions/injector.js\";\nimport { groupByInstructFile } from \"../instructions/templates.js\";\nimport { type InstallResult, installMcpServer } from \"../mcp/installer.js\";\nimport { listMcpServers, resolveConfigPath } from \"../mcp/reader.js\";\nimport { getTransform } from \"../mcp/transforms.js\";\nimport { CANONICAL_SKILLS_DIR } from \"../paths/agents.js\";\nimport { getInstalledProviders } from \"../registry/detection.js\";\nimport { installSkill, removeSkill } from \"../skills/installer.js\";\n\ntype Scope = \"project\" | \"global\";\n\nconst PRIORITY_ORDER: Record<ProviderPriority, number> = {\n high: 0,\n medium: 1,\n low: 2,\n};\n\n/**\n * Filters providers by minimum priority and returns them in deterministic tier order.\n *\n * @remarks\n * Providers are filtered to include only those at or above the specified priority\n * level, then sorted from highest to lowest priority. For example,\n * `minimumPriority = \"medium\"` returns providers with `high` and `medium` priority.\n *\n * @param providers - The full list of providers to filter\n * @param minimumPriority - The minimum priority threshold, defaults to `\"low\"` (include all)\n * @returns A filtered and sorted array of providers meeting the priority threshold\n *\n * @example\n * ```typescript\n * const highPriority = selectProvidersByMinimumPriority(allProviders, \"high\");\n * // returns only providers with priority \"high\"\n * ```\n *\n * @public\n */\nexport function selectProvidersByMinimumPriority(\n providers: Provider[],\n minimumPriority: ProviderPriority = \"low\",\n): Provider[] {\n const maxRank = PRIORITY_ORDER[minimumPriority];\n\n return [...providers]\n .filter((provider) => PRIORITY_ORDER[provider.priority] <= maxRank)\n .sort((a, b) => PRIORITY_ORDER[a.priority] - PRIORITY_ORDER[b.priority]);\n}\n\n/**\n * Single MCP operation entry used by batch orchestration.\n *\n * @remarks\n * Represents one MCP server installation that will be applied across\n * all targeted providers during a batch operation.\n *\n * @public\n */\nexport interface McpBatchOperation {\n /** The name of the MCP server to install. */\n serverName: string;\n /** The MCP server configuration to write. */\n config: McpServerConfig;\n /** The scope for installation, defaults to `\"project\"`. */\n scope?: Scope;\n}\n\n/**\n * Single skill operation entry used by batch orchestration.\n *\n * @remarks\n * Represents one skill installation that will be applied across\n * all targeted providers during a batch operation.\n *\n * @public\n */\nexport interface SkillBatchOperation {\n /** The filesystem path to the skill source files. */\n sourcePath: string;\n /** The unique name for the skill being installed. */\n skillName: string;\n /** Whether to install globally or project-scoped, defaults to true. */\n isGlobal?: boolean;\n}\n\n/**\n * Options for rollback-capable batch installation.\n *\n * @remarks\n * All fields are optional. When providers are not specified, installed\n * providers are auto-detected. When minimumPriority is not specified,\n * all priority levels are included.\n *\n * @public\n */\nexport interface BatchInstallOptions {\n /** Explicit list of providers to target, auto-detected if omitted. */\n providers?: Provider[];\n /** Minimum provider priority threshold for filtering. */\n minimumPriority?: ProviderPriority;\n /** MCP server operations to apply in the batch. */\n mcp?: McpBatchOperation[];\n /** Skill operations to apply in the batch. */\n skills?: SkillBatchOperation[];\n /** Project root directory, defaults to `process.cwd()`. */\n projectDir?: string;\n}\n\n/**\n * Result of rollback-capable batch installation.\n *\n * @remarks\n * When `success` is false, `rollbackPerformed` indicates whether rollback\n * was attempted. Any errors during rollback are captured in `rollbackErrors`.\n *\n * @public\n */\nexport interface BatchInstallResult {\n /** Whether all operations completed successfully. */\n success: boolean;\n /** IDs of providers that were targeted. */\n providerIds: string[];\n /** Number of MCP server installations that were applied. */\n mcpApplied: number;\n /** Number of skill installations that were applied. */\n skillsApplied: number;\n /** Whether rollback was performed due to a failure. */\n rollbackPerformed: boolean;\n /** Error messages from any failures during rollback. */\n rollbackErrors: string[];\n /** Error message from the operation that triggered rollback. */\n error?: string;\n}\n\ninterface SkillPathSnapshot {\n linkPath: string;\n state: \"missing\" | \"symlink\" | \"directory\" | \"file\";\n symlinkTarget?: string;\n backupPath?: string;\n}\n\ninterface SkillSnapshot {\n skillName: string;\n isGlobal: boolean;\n canonicalPath: string;\n canonicalBackupPath?: string;\n canonicalExisted: boolean;\n pathSnapshots: SkillPathSnapshot[];\n}\n\ninterface AppliedSkillInstall {\n skillName: string;\n isGlobal: boolean;\n linkedProviders: Provider[];\n}\n\nfunction resolveSkillLinkPath(\n provider: Provider,\n skillName: string,\n isGlobal: boolean,\n projectDir: string,\n): string {\n const skillDir = isGlobal\n ? provider.pathSkills\n : join(projectDir, provider.pathProjectSkills);\n return join(skillDir, skillName);\n}\n\nasync function snapshotConfigs(paths: string[]): Promise<Map<string, string | null>> {\n const snapshots = new Map<string, string | null>();\n\n for (const path of paths) {\n if (!path || snapshots.has(path)) continue;\n if (!existsSync(path)) {\n snapshots.set(path, null);\n continue;\n }\n snapshots.set(path, await readFile(path, \"utf-8\"));\n }\n\n return snapshots;\n}\n\nasync function restoreConfigSnapshots(snapshots: Map<string, string | null>): Promise<void> {\n for (const [path, content] of snapshots) {\n if (content === null) {\n await rm(path, { force: true });\n continue;\n }\n\n await mkdir(dirname(path), { recursive: true });\n await writeFile(path, content, \"utf-8\");\n }\n}\n\nasync function snapshotSkillState(\n providerTargets: Provider[],\n operation: SkillBatchOperation,\n projectDir: string,\n backupRoot: string,\n): Promise<SkillSnapshot> {\n const skillName = operation.skillName;\n const isGlobal = operation.isGlobal ?? true;\n const canonicalPath = join(CANONICAL_SKILLS_DIR, skillName);\n const canonicalExisted = existsSync(canonicalPath);\n const canonicalBackupPath = join(backupRoot, \"canonical\", skillName);\n\n if (canonicalExisted) {\n await mkdir(dirname(canonicalBackupPath), { recursive: true });\n await cp(canonicalPath, canonicalBackupPath, { recursive: true });\n }\n\n const pathSnapshots: SkillPathSnapshot[] = [];\n for (const provider of providerTargets) {\n const linkPath = resolveSkillLinkPath(provider, skillName, isGlobal, projectDir);\n\n if (!existsSync(linkPath)) {\n pathSnapshots.push({ linkPath, state: \"missing\" });\n continue;\n }\n\n const stat = lstatSync(linkPath);\n\n if (stat.isSymbolicLink()) {\n pathSnapshots.push({\n linkPath,\n state: \"symlink\",\n symlinkTarget: await readlink(linkPath),\n });\n continue;\n }\n\n const backupPath = join(backupRoot, \"links\", provider.id, `${skillName}-${basename(linkPath)}`);\n await mkdir(dirname(backupPath), { recursive: true });\n\n if (stat.isDirectory()) {\n await cp(linkPath, backupPath, { recursive: true });\n pathSnapshots.push({ linkPath, state: \"directory\", backupPath });\n continue;\n }\n\n await cp(linkPath, backupPath);\n pathSnapshots.push({ linkPath, state: \"file\", backupPath });\n }\n\n return {\n skillName,\n isGlobal,\n canonicalPath,\n canonicalBackupPath: canonicalExisted ? canonicalBackupPath : undefined,\n canonicalExisted,\n pathSnapshots,\n };\n}\n\nasync function restoreSkillSnapshot(snapshot: SkillSnapshot): Promise<void> {\n if (existsSync(snapshot.canonicalPath)) {\n await rm(snapshot.canonicalPath, { recursive: true, force: true });\n }\n\n if (snapshot.canonicalExisted && snapshot.canonicalBackupPath && existsSync(snapshot.canonicalBackupPath)) {\n await mkdir(dirname(snapshot.canonicalPath), { recursive: true });\n await cp(snapshot.canonicalBackupPath, snapshot.canonicalPath, { recursive: true });\n }\n\n for (const pathSnapshot of snapshot.pathSnapshots) {\n await rm(pathSnapshot.linkPath, { recursive: true, force: true });\n\n if (pathSnapshot.state === \"missing\") continue;\n\n await mkdir(dirname(pathSnapshot.linkPath), { recursive: true });\n\n if (pathSnapshot.state === \"symlink\" && pathSnapshot.symlinkTarget) {\n const linkType = process.platform === \"win32\" ? \"junction\" : \"dir\";\n await symlink(pathSnapshot.symlinkTarget, pathSnapshot.linkPath, linkType);\n continue;\n }\n\n if ((pathSnapshot.state === \"directory\" || pathSnapshot.state === \"file\") && pathSnapshot.backupPath) {\n if (pathSnapshot.state === \"directory\") {\n await cp(pathSnapshot.backupPath, pathSnapshot.linkPath, { recursive: true });\n } else {\n await cp(pathSnapshot.backupPath, pathSnapshot.linkPath);\n }\n }\n }\n}\n\n/**\n * Installs multiple MCP servers and skills across filtered providers with rollback.\n *\n * @remarks\n * Snapshots all affected config files and skill directories before applying\n * operations. If any operation fails, all changes are rolled back by restoring\n * config file snapshots and reverting skill symlinks and canonical directories\n * to their pre-operation state.\n *\n * @param options - The batch installation options including providers, operations, and scope\n * @returns A result object indicating success, applied counts, and any rollback information\n *\n * @example\n * ```typescript\n * const result = await installBatchWithRollback({\n * minimumPriority: \"high\",\n * mcp: [{ serverName: \"my-server\", config: { command: \"npx\", args: [\"my-server\"] } }],\n * skills: [{ sourcePath: \"/path/to/skill\", skillName: \"my-skill\" }],\n * });\n * if (!result.success) {\n * console.error(\"Failed:\", result.error);\n * }\n * ```\n *\n * @public\n */\nexport async function installBatchWithRollback(\n options: BatchInstallOptions,\n): Promise<BatchInstallResult> {\n const projectDir = options.projectDir ?? process.cwd();\n const minimumPriority = options.minimumPriority ?? \"low\";\n const mcpOps = options.mcp ?? [];\n const skillOps = options.skills ?? [];\n const baseProviders = options.providers ?? getInstalledProviders();\n const providers = selectProvidersByMinimumPriority(baseProviders, minimumPriority);\n\n const configPaths = providers.flatMap((provider) => {\n const paths: string[] = [];\n for (const operation of mcpOps) {\n const path = resolveConfigPath(provider, operation.scope ?? \"project\", projectDir);\n if (path) paths.push(path);\n }\n return paths;\n });\n\n const configSnapshots = await snapshotConfigs(configPaths);\n const backupRoot = join(\n tmpdir(),\n `caamp-skill-backup-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,\n );\n\n const skillSnapshots = await Promise.all(\n skillOps.map((operation) => snapshotSkillState(providers, operation, projectDir, backupRoot)),\n );\n\n const appliedSkills: AppliedSkillInstall[] = [];\n const rollbackErrors: string[] = [];\n let mcpApplied = 0;\n let skillsApplied = 0;\n let rollbackPerformed = false;\n\n try {\n for (const operation of mcpOps) {\n const scope = operation.scope ?? \"project\";\n for (const provider of providers) {\n const result = await installMcpServer(\n provider,\n operation.serverName,\n operation.config,\n scope,\n projectDir,\n );\n\n if (!result.success) {\n throw new Error(result.error ?? `Failed MCP install for ${provider.id}`);\n }\n mcpApplied += 1;\n }\n }\n\n for (const operation of skillOps) {\n const isGlobal = operation.isGlobal ?? true;\n const result = await installSkill(\n operation.sourcePath,\n operation.skillName,\n providers,\n isGlobal,\n projectDir,\n );\n\n const linkedProviders = providers.filter((provider) => result.linkedAgents.includes(provider.id));\n appliedSkills.push({\n skillName: operation.skillName,\n isGlobal,\n linkedProviders,\n });\n\n if (result.errors.length > 0) {\n throw new Error(result.errors.join(\"; \"));\n }\n\n skillsApplied += 1;\n }\n\n await rm(backupRoot, { recursive: true, force: true });\n\n return {\n success: true,\n providerIds: providers.map((provider) => provider.id),\n mcpApplied,\n skillsApplied,\n rollbackPerformed: false,\n rollbackErrors: [],\n };\n } catch (error) {\n rollbackPerformed = true;\n\n for (const applied of [...appliedSkills].reverse()) {\n try {\n await removeSkill(applied.skillName, applied.linkedProviders, applied.isGlobal, projectDir);\n } catch (err) {\n rollbackErrors.push(err instanceof Error ? err.message : String(err));\n }\n }\n\n try {\n await restoreConfigSnapshots(configSnapshots);\n } catch (err) {\n rollbackErrors.push(err instanceof Error ? err.message : String(err));\n }\n\n for (const snapshot of skillSnapshots) {\n try {\n await restoreSkillSnapshot(snapshot);\n } catch (err) {\n rollbackErrors.push(err instanceof Error ? err.message : String(err));\n }\n }\n\n await rm(backupRoot, { recursive: true, force: true });\n\n return {\n success: false,\n providerIds: providers.map((provider) => provider.id),\n mcpApplied,\n skillsApplied,\n rollbackPerformed,\n rollbackErrors,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n}\n\n/**\n * Conflict policy when applying MCP install plans.\n *\n * @remarks\n * Controls behavior when an existing MCP server configuration conflicts\n * with the desired configuration: `\"fail\"` aborts the entire operation,\n * `\"skip\"` leaves conflicting entries unchanged, and `\"overwrite\"` replaces them.\n *\n * @public\n */\nexport type ConflictPolicy = \"fail\" | \"skip\" | \"overwrite\";\n\n/**\n * Conflict code identifying the type of MCP configuration conflict.\n *\n * @remarks\n * Used in {@link McpConflict} to categorize detected conflicts during\n * preflight checks before applying MCP installations.\n *\n * @public\n */\nexport type McpConflictCode =\n | \"unsupported-transport\"\n | \"unsupported-headers\"\n | \"existing-mismatch\";\n\n/**\n * Describes a conflict detected during MCP installation preflight.\n *\n * @remarks\n * Contains the provider, server, scope, and nature of the conflict\n * so that callers can decide how to proceed based on their conflict policy.\n *\n * @public\n */\nexport interface McpConflict {\n /** The provider where the conflict was detected. */\n providerId: string;\n /** The MCP server name involved in the conflict. */\n serverName: string;\n /** The scope (global or project) of the conflicting config. */\n scope: Scope;\n /** The type of conflict detected. */\n code: McpConflictCode;\n /** Human-readable description of the conflict. */\n message: string;\n}\n\n/**\n * Result from applying an MCP install plan with a conflict policy.\n *\n * @remarks\n * Contains all detected conflicts, successfully applied installations,\n * and any operations that were skipped due to the conflict policy.\n *\n * @public\n */\nexport interface McpPlanApplyResult {\n /** All conflicts detected during preflight, regardless of policy. */\n conflicts: McpConflict[];\n /** Successfully applied MCP server installations. */\n applied: InstallResult[];\n /** Operations skipped due to the conflict policy. */\n skipped: Array<{\n providerId: string;\n serverName: string;\n scope: Scope;\n reason: McpConflictCode;\n }>;\n}\n\nfunction stableStringify(value: unknown): string {\n if (Array.isArray(value)) {\n return `[${value.map(stableStringify).join(\",\")}]`;\n }\n\n if (value && typeof value === \"object\") {\n const record = value as Record<string, unknown>;\n const keys = Object.keys(record).sort();\n return `{${keys.map((key) => `${JSON.stringify(key)}:${stableStringify(record[key])}`).join(\",\")}}`;\n }\n\n return JSON.stringify(value);\n}\n\n/**\n * Performs preflight conflict detection for MCP install plans across providers.\n *\n * @remarks\n * Checks each provider-operation pair for transport support, header support,\n * and existing configuration mismatches. Returns all detected conflicts without\n * modifying any files. Callers can then decide whether to proceed based on\n * their conflict policy.\n *\n * @param providers - The providers to check for conflicts\n * @param operations - The MCP operations to validate against existing configs\n * @param projectDir - The project root directory, defaults to `process.cwd()`\n * @returns An array of detected conflicts, empty if no conflicts found\n *\n * @example\n * ```typescript\n * const conflicts = await detectMcpConfigConflicts(providers, operations);\n * if (conflicts.length > 0) {\n * console.warn(\"Conflicts detected:\", conflicts);\n * }\n * ```\n *\n * @public\n */\nexport async function detectMcpConfigConflicts(\n providers: Provider[],\n operations: McpBatchOperation[],\n projectDir = process.cwd(),\n): Promise<McpConflict[]> {\n const conflicts: McpConflict[] = [];\n\n for (const provider of providers) {\n for (const operation of operations) {\n const scope = operation.scope ?? \"project\";\n\n if (operation.config.type && !provider.supportedTransports.includes(operation.config.type)) {\n conflicts.push({\n providerId: provider.id,\n serverName: operation.serverName,\n scope,\n code: \"unsupported-transport\",\n message: `${provider.id} does not support transport ${operation.config.type}`,\n });\n }\n\n if (operation.config.headers && !provider.supportsHeaders) {\n conflicts.push({\n providerId: provider.id,\n serverName: operation.serverName,\n scope,\n code: \"unsupported-headers\",\n message: `${provider.id} does not support header configuration`,\n });\n }\n\n const existingEntries = await listMcpServers(provider, scope, projectDir);\n const current = existingEntries.find((entry) => entry.name === operation.serverName);\n if (!current) continue;\n\n const transform = getTransform(provider.id);\n const desired = transform\n ? transform(operation.serverName, operation.config)\n : operation.config;\n\n if (stableStringify(current.config) !== stableStringify(desired)) {\n conflicts.push({\n providerId: provider.id,\n serverName: operation.serverName,\n scope,\n code: \"existing-mismatch\",\n message: `${provider.id} has existing config mismatch for ${operation.serverName}`,\n });\n }\n }\n }\n\n return conflicts;\n}\n\n/**\n * Applies an MCP install plan with a conflict policy controlling behavior on conflicts.\n *\n * @remarks\n * First runs {@link detectMcpConfigConflicts} to find all conflicts, then applies\n * the specified policy: `\"fail\"` returns immediately with no changes, `\"skip\"`\n * leaves conflicting entries unchanged and applies the rest, and `\"overwrite\"`\n * applies all operations regardless of conflicts.\n *\n * @param providers - The providers to install MCP servers for\n * @param operations - The MCP server operations to apply\n * @param policy - The conflict resolution policy, defaults to `\"fail\"`\n * @param projectDir - The project root directory, defaults to `process.cwd()`\n * @returns A result containing conflicts, applied installations, and skipped operations\n *\n * @example\n * ```typescript\n * const result = await applyMcpInstallWithPolicy(providers, operations, \"skip\");\n * console.log(`Applied: ${result.applied.length}, Skipped: ${result.skipped.length}`);\n * ```\n *\n * @public\n */\nexport async function applyMcpInstallWithPolicy(\n providers: Provider[],\n operations: McpBatchOperation[],\n policy: ConflictPolicy = \"fail\",\n projectDir = process.cwd(),\n): Promise<McpPlanApplyResult> {\n const conflicts = await detectMcpConfigConflicts(providers, operations, projectDir);\n const conflictKey = (providerId: string, serverName: string, scope: Scope) => `${providerId}::${serverName}::${scope}`;\n const conflictMap = new Map<string, McpConflict>();\n for (const conflict of conflicts) {\n conflictMap.set(conflictKey(conflict.providerId, conflict.serverName, conflict.scope), conflict);\n }\n\n if (policy === \"fail\" && conflicts.length > 0) {\n return { conflicts, applied: [], skipped: [] };\n }\n\n const applied: InstallResult[] = [];\n const skipped: McpPlanApplyResult[\"skipped\"] = [];\n\n for (const provider of providers) {\n for (const operation of operations) {\n const scope = operation.scope ?? \"project\";\n const key = conflictKey(provider.id, operation.serverName, scope);\n const conflict = conflictMap.get(key);\n\n if (policy === \"skip\" && conflict) {\n skipped.push({\n providerId: provider.id,\n serverName: operation.serverName,\n scope,\n reason: conflict.code,\n });\n continue;\n }\n\n const result = await installMcpServer(\n provider,\n operation.serverName,\n operation.config,\n scope,\n projectDir,\n );\n applied.push(result);\n }\n }\n\n return { conflicts, applied, skipped };\n}\n\n/**\n * Result of a single-operation instruction update across providers.\n *\n * @remarks\n * Summarizes the instruction files that were created, updated, or left\n * intact during an instruction injection operation.\n *\n * @public\n */\nexport interface InstructionUpdateSummary {\n /** The scope at which instructions were updated. */\n scope: Scope;\n /** The total number of instruction files that were modified. */\n updatedFiles: number;\n /** Detailed action log per instruction file. */\n actions: Array<{\n file: string;\n action: \"created\" | \"added\" | \"consolidated\" | \"updated\" | \"intact\";\n providers: string[];\n configFormats: ConfigFormat[];\n }>;\n}\n\n/**\n * Updates instruction files across providers as a single operation.\n *\n * @remarks\n * Works the same regardless of provider config format (JSON/YAML/TOML/JSONC)\n * because instruction files are handled through CAAMP markers. Groups\n * providers by their instruction file targets and injects content using\n * marker-based sections.\n *\n * @param providers - The providers whose instruction files to update\n * @param content - The instruction content to inject\n * @param scope - The scope for instruction updates, defaults to `\"project\"`\n * @param projectDir - The project root directory, defaults to `process.cwd()`\n * @returns A summary of updated files and actions taken per file\n *\n * @example\n * ```typescript\n * const summary = await updateInstructionsSingleOperation(\n * providers,\n * \"## CAAMP Config\\nUse these MCP servers...\",\n * \"project\",\n * );\n * console.log(`Updated ${summary.updatedFiles} files`);\n * ```\n *\n * @public\n */\nexport async function updateInstructionsSingleOperation(\n providers: Provider[],\n content: string,\n scope: Scope = \"project\",\n projectDir = process.cwd(),\n): Promise<InstructionUpdateSummary> {\n const actions = await injectAll(providers, projectDir, scope, content);\n const groupedByFile = groupByInstructFile(providers);\n\n const summary: InstructionUpdateSummary = {\n scope,\n updatedFiles: actions.size,\n actions: [],\n };\n\n for (const [filePath, action] of actions.entries()) {\n const providersForFile = providers.filter((provider) => {\n const expectedPath = scope === \"global\"\n ? join(provider.pathGlobal, provider.instructFile)\n : join(projectDir, provider.instructFile);\n return expectedPath === filePath;\n });\n\n const fallback = groupedByFile.get(basename(filePath)) ?? [];\n const selected = providersForFile.length > 0 ? providersForFile : fallback;\n\n summary.actions.push({\n file: filePath,\n action,\n providers: selected.map((provider) => provider.id),\n configFormats: Array.from(new Set(selected.map((provider) => provider.configFormat))),\n });\n }\n\n return summary;\n}\n\n/**\n * Request payload for dual-scope provider configuration.\n *\n * @remarks\n * Allows configuring both global and project-level MCP servers and\n * instructions in a single call. Instruction content can be a single\n * string applied to both scopes or scope-specific strings.\n *\n * @public\n */\nexport interface DualScopeConfigureOptions {\n /** MCP servers to install at global scope. */\n globalMcp?: Array<{ serverName: string; config: McpServerConfig }>;\n /** MCP servers to install at project scope. */\n projectMcp?: Array<{ serverName: string; config: McpServerConfig }>;\n /** Instruction content for injection, either shared or per-scope. */\n instructionContent?: string | { global?: string; project?: string };\n /** Project root directory, defaults to `process.cwd()`. */\n projectDir?: string;\n}\n\n/**\n * Result of dual-scope provider configuration.\n *\n * @remarks\n * Contains the resolved config paths, MCP installation results for both\n * scopes, and instruction injection results for each scope that was configured.\n *\n * @public\n */\nexport interface DualScopeConfigureResult {\n /** The ID of the configured provider. */\n providerId: string;\n /** Resolved configuration file paths for both scopes. */\n configPaths: {\n global: string | null;\n project: string | null;\n };\n /** MCP installation results for each scope. */\n mcp: {\n global: InstallResult[];\n project: InstallResult[];\n };\n /** Instruction injection results for each scope, if applicable. */\n instructions: {\n global?: Map<string, \"created\" | \"added\" | \"consolidated\" | \"updated\" | \"intact\">;\n project?: Map<string, \"created\" | \"added\" | \"consolidated\" | \"updated\" | \"intact\">;\n };\n}\n\n/**\n * Configures both global and project-level settings for one provider in one call.\n *\n * @remarks\n * Applies MCP server installations and instruction injections at both global\n * and project scope in a single coordinated operation. This avoids the need\n * to make separate calls for each scope.\n *\n * @param provider - The provider to configure\n * @param options - The dual-scope configuration options\n * @returns A result containing config paths, MCP results, and instruction results for both scopes\n *\n * @example\n * ```typescript\n * const result = await configureProviderGlobalAndProject(provider, {\n * globalMcp: [{ serverName: \"my-server\", config: { command: \"npx\", args: [\"my-server\"] } }],\n * instructionContent: \"## Agent Setup\\nUse these tools...\",\n * });\n * console.log(result.configPaths);\n * ```\n *\n * @public\n */\nexport async function configureProviderGlobalAndProject(\n provider: Provider,\n options: DualScopeConfigureOptions,\n): Promise<DualScopeConfigureResult> {\n const projectDir = options.projectDir ?? process.cwd();\n const globalOps = options.globalMcp ?? [];\n const projectOps = options.projectMcp ?? [];\n\n const globalResults: InstallResult[] = [];\n for (const operation of globalOps) {\n globalResults.push(await installMcpServer(\n provider,\n operation.serverName,\n operation.config,\n \"global\",\n projectDir,\n ));\n }\n\n const projectResults: InstallResult[] = [];\n for (const operation of projectOps) {\n projectResults.push(await installMcpServer(\n provider,\n operation.serverName,\n operation.config,\n \"project\",\n projectDir,\n ));\n }\n\n const instructionResults: DualScopeConfigureResult[\"instructions\"] = {};\n const instructionContent = options.instructionContent;\n if (typeof instructionContent === \"string\") {\n instructionResults.global = await injectAll([provider], projectDir, \"global\", instructionContent);\n instructionResults.project = await injectAll([provider], projectDir, \"project\", instructionContent);\n } else if (instructionContent) {\n if (instructionContent.global) {\n instructionResults.global = await injectAll([provider], projectDir, \"global\", instructionContent.global);\n }\n if (instructionContent.project) {\n instructionResults.project = await injectAll([provider], projectDir, \"project\", instructionContent.project);\n }\n }\n\n return {\n providerId: provider.id,\n configPaths: {\n global: resolveConfigPath(provider, \"global\", projectDir),\n project: resolveConfigPath(provider, \"project\", projectDir),\n },\n mcp: {\n global: globalResults,\n project: projectResults,\n },\n instructions: instructionResults,\n };\n}\n","import {\n getAgentsHome,\n getCanonicalSkillsDir,\n getLockFilePath,\n getAgentsMcpDir,\n getAgentsMcpServersPath,\n getAgentsConfigPath,\n} from \"./standard.js\";\n\n/**\n * Global `.agents/` home directory (`~/.agents/` or `$AGENTS_HOME`).\n * @public\n */\nexport const AGENTS_HOME = getAgentsHome();\n\n/**\n * CAAMP lock file path (`~/.agents/.caamp-lock.json`).\n * @public\n */\nexport const LOCK_FILE_PATH = getLockFilePath();\n\n/**\n * Canonical skills directory (`~/.agents/skills/`).\n * @public\n */\nexport const CANONICAL_SKILLS_DIR = getCanonicalSkillsDir();\n\n/**\n * Global MCP directory (`~/.agents/mcp/`).\n * @public\n */\nexport const AGENTS_MCP_DIR = getAgentsMcpDir();\n\n/**\n * Global MCP servers.json path (`~/.agents/mcp/servers.json`).\n * @public\n */\nexport const AGENTS_MCP_SERVERS_PATH = getAgentsMcpServersPath();\n\n/**\n * Global agents config.toml path (`~/.agents/config.toml`).\n * @public\n */\nexport const AGENTS_CONFIG_PATH = getAgentsConfigPath();\n","/**\n * CLEO MCP channel profile helpers.\n */\n\nimport { execFileSync } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { isAbsolute, resolve } from \"node:path\";\nimport type { McpServerConfig } from \"../../types.js\";\n\n/**\n * CLEO release channel identifier.\n *\n * @remarks\n * Determines which version stream is used: `\"stable\"` for production releases,\n * `\"beta\"` for pre-release versions, and `\"dev\"` for local development builds.\n *\n * @public\n */\nexport type CleoChannel = \"stable\" | \"beta\" | \"dev\";\n\n/**\n * Mapping of CLEO channels to their MCP server names.\n *\n * @remarks\n * Each channel has a distinct server name to allow multiple channels to\n * coexist in the same MCP configuration without conflicting.\n *\n * @public\n */\nexport const CLEO_SERVER_NAMES: Record<CleoChannel, string> = {\n stable: \"cleo\",\n beta: \"cleo-beta\",\n dev: \"cleo-dev\",\n};\n\n/**\n * The npm package name for the CLEO MCP server.\n *\n * @remarks\n * Used as the base package specifier when constructing npx commands\n * for stable and beta channel installations.\n *\n * @public\n */\nexport const CLEO_MCP_NPM_PACKAGE = \"@cleocode/cleo\";\n\n/**\n * Default directory path for CLEO dev channel data.\n *\n * @remarks\n * Expanded from `~` at runtime. Used as the `CLEO_DIR` environment\n * variable when no explicit directory is provided for dev channel profiles.\n *\n * @public\n */\nexport const CLEO_DEV_DIR_DEFAULT = \"~/.cleo-dev\";\n\n/**\n * Options for building a CLEO MCP server profile configuration.\n *\n * @remarks\n * For stable and beta channels, the `version` field controls the npm package\n * version. For the dev channel, `command` is required to specify the local\n * binary path or command.\n *\n * @public\n */\nexport interface CleoProfileBuildOptions {\n /** The CLEO release channel to target. */\n channel: CleoChannel;\n /** Optional npm version tag or semver range for stable/beta channels. */\n version?: string;\n /** Custom command binary for dev channel, required when channel is `\"dev\"`. */\n command?: string;\n /** Additional arguments to pass to the command. */\n args?: string[];\n /** Environment variables to set in the MCP server config. */\n env?: Record<string, string>;\n /** Custom CLEO directory path for dev channel, overrides default. */\n cleoDir?: string;\n}\n\n/**\n * Result of building a CLEO MCP server profile configuration.\n *\n * @remarks\n * Contains the resolved channel, server name, and MCP configuration.\n * For stable/beta channels, `packageSpec` contains the npm package\n * specifier used in the npx command.\n *\n * @public\n */\nexport interface CleoProfileBuildResult {\n /** The resolved CLEO release channel. */\n channel: CleoChannel;\n /** The MCP server name for this channel. */\n serverName: string;\n /** The MCP server configuration ready for installation. */\n config: McpServerConfig;\n /** The npm package specifier, present for stable/beta channels. */\n packageSpec?: string;\n}\n\n/**\n * Result of checking whether a command is reachable on the system.\n *\n * @remarks\n * The `method` field indicates whether the command was checked as a filesystem\n * path or via system PATH lookup (using `which`/`where`).\n *\n * @public\n */\nexport interface CommandReachability {\n /** Whether the command was found and is reachable. */\n reachable: boolean;\n /** The method used to check reachability. */\n method: \"path\" | \"lookup\";\n /** The resolved path or command name that was checked. */\n detail: string;\n}\n\n/**\n * Normalizes a string value to a valid CLEO channel identifier.\n *\n * @remarks\n * Trims and lowercases the input, then validates it against the known\n * channel names. Returns `\"stable\"` for empty or undefined input.\n * Throws if the value is not a recognized channel.\n *\n * @param value - The raw channel string to normalize\n * @returns The normalized CLEO channel\n * @throws Error if the value is not `\"stable\"`, `\"beta\"`, or `\"dev\"`\n *\n * @example\n * ```typescript\n * const channel = normalizeCleoChannel(\"Beta\");\n * // returns \"beta\"\n * ```\n *\n * @public\n */\nexport function normalizeCleoChannel(value?: string): CleoChannel {\n if (!value || value.trim() === \"\") return \"stable\";\n const normalized = value.trim().toLowerCase();\n if (normalized === \"stable\" || normalized === \"beta\" || normalized === \"dev\") {\n return normalized;\n }\n throw new Error(`Invalid channel \\\"${value}\\\". Expected stable, beta, or dev.`);\n}\n\n/**\n * Resolves the MCP server name for a given CLEO channel.\n *\n * @remarks\n * Maps channel identifiers to their corresponding server names\n * using the {@link CLEO_SERVER_NAMES} registry.\n *\n * @param channel - The CLEO channel to resolve\n * @returns The MCP server name for the channel\n *\n * @example\n * ```typescript\n * const name = resolveCleoServerName(\"stable\");\n * // returns \"cleo\"\n * ```\n *\n * @public\n */\nexport function resolveCleoServerName(channel: CleoChannel): string {\n return CLEO_SERVER_NAMES[channel];\n}\n\n/**\n * Resolves a CLEO channel from an MCP server name.\n *\n * @remarks\n * Performs a reverse lookup from server name to channel. Returns null\n * if the server name does not match any known CLEO channel.\n *\n * @param serverName - The MCP server name to look up\n * @returns The matching CLEO channel, or null if not a CLEO server\n *\n * @example\n * ```typescript\n * const channel = resolveChannelFromServerName(\"cleo-beta\");\n * // returns \"beta\"\n * ```\n *\n * @public\n */\nexport function resolveChannelFromServerName(serverName: string): CleoChannel | null {\n if (serverName === CLEO_SERVER_NAMES.stable) return \"stable\";\n if (serverName === CLEO_SERVER_NAMES.beta) return \"beta\";\n if (serverName === CLEO_SERVER_NAMES.dev) return \"dev\";\n return null;\n}\n\nfunction splitCommand(command: string, explicitArgs: string[] = []): { command: string; args: string[] } {\n if (explicitArgs.length > 0) {\n return { command, args: explicitArgs };\n }\n const parts = command.trim().split(/\\s+/);\n const binary = parts[0] ?? \"\";\n if (!binary) {\n throw new Error(\"Command is required for dev channel.\");\n }\n return {\n command: binary,\n args: parts.slice(1),\n };\n}\n\nfunction normalizeEnv(\n env: Record<string, string> | undefined,\n channel: CleoChannel,\n cleoDir?: string,\n): Record<string, string> | undefined {\n const result = { ...(env ?? {}) };\n if (channel === \"dev\" && !result.CLEO_DIR) {\n result.CLEO_DIR = cleoDir ?? CLEO_DEV_DIR_DEFAULT;\n }\n return Object.keys(result).length > 0 ? result : undefined;\n}\n\nfunction resolvePackageSpec(channel: CleoChannel, version?: string): string {\n const tag = version?.trim() || (channel === \"stable\" ? \"latest\" : \"beta\");\n return `${CLEO_MCP_NPM_PACKAGE}@${tag}`;\n}\n\n/**\n * Builds a CLEO MCP server profile configuration from options.\n *\n * @remarks\n * For the dev channel, constructs a config using the provided command and args.\n * For stable/beta channels, constructs an npx-based config with the appropriate\n * package specifier. Dev channel requires a command; stable/beta use npx with\n * the `@cleocode/cleo` package.\n *\n * @param options - The profile build options specifying channel, command, version, etc.\n * @returns The built profile with server name, config, and optional package spec\n * @throws Error if dev channel is selected without a command\n *\n * @example\n * ```typescript\n * const profile = buildCleoProfile({ channel: \"stable\" });\n * // profile.config.command === \"npx\"\n * // profile.config.args === [\"-y\", \"@cleocode/cleo@latest\", \"mcp\"]\n * ```\n *\n * @public\n */\nexport function buildCleoProfile(options: CleoProfileBuildOptions): CleoProfileBuildResult {\n const channel = options.channel;\n const serverName = resolveCleoServerName(channel);\n\n if (channel === \"dev\") {\n if (!options.command || options.command.trim() === \"\") {\n throw new Error(\"Dev channel requires --command.\");\n }\n\n const parsed = splitCommand(options.command, options.args ?? []);\n const env = normalizeEnv(options.env, channel, options.cleoDir);\n return {\n channel,\n serverName,\n config: {\n command: parsed.command,\n args: parsed.args,\n ...(env ? { env } : {}),\n },\n };\n }\n\n const packageSpec = resolvePackageSpec(channel, options.version);\n return {\n channel,\n serverName,\n packageSpec,\n config: {\n command: \"npx\",\n args: [\"-y\", packageSpec, \"mcp\"],\n },\n };\n}\n\nfunction expandHome(pathValue: string): string {\n if (pathValue === \"~\") return homedir();\n if (pathValue.startsWith(\"~/\")) {\n return resolve(homedir(), pathValue.slice(2));\n }\n return pathValue;\n}\n\n/**\n * Checks whether a command binary is reachable on the current system.\n *\n * @remarks\n * If the command contains path separators or starts with `~`, it is treated\n * as a filesystem path and checked with `existsSync`. Otherwise, a system\n * PATH lookup is performed using `which` (Unix) or `where` (Windows).\n *\n * @param command - The command or path to check for reachability\n * @returns A reachability result indicating whether the command was found\n *\n * @example\n * ```typescript\n * const result = checkCommandReachability(\"node\");\n * if (result.reachable) {\n * console.log(\"Found via\", result.method);\n * }\n * ```\n *\n * @public\n */\nexport function checkCommandReachability(command: string): CommandReachability {\n const hasPathSeparator = command.includes(\"/\") || command.includes(\"\\\\\");\n if (hasPathSeparator || command.startsWith(\"~\")) {\n const expanded = expandHome(command);\n const candidate = isAbsolute(expanded) ? expanded : resolve(process.cwd(), expanded);\n if (existsSync(candidate)) {\n return { reachable: true, method: \"path\", detail: candidate };\n }\n return { reachable: false, method: \"path\", detail: candidate };\n }\n\n try {\n const lookup = process.platform === \"win32\" ? \"where\" : \"which\";\n execFileSync(lookup, [command], { stdio: \"pipe\" });\n return { reachable: true, method: \"lookup\", detail: command };\n } catch {\n return { reachable: false, method: \"lookup\", detail: command };\n }\n}\n\n/**\n * Parses an array of `KEY=value` strings into an environment variable record.\n *\n * @remarks\n * Each string must contain an `=` separator with a non-empty key.\n * Throws on malformed entries. Whitespace around keys and values is trimmed.\n *\n * @param values - Array of `KEY=value` assignment strings\n * @returns A record mapping environment variable names to their values\n * @throws Error if any assignment is malformed (missing `=` or empty key)\n *\n * @example\n * ```typescript\n * const env = parseEnvAssignments([\"NODE_ENV=production\", \"PORT=3000\"]);\n * // returns { NODE_ENV: \"production\", PORT: \"3000\" }\n * ```\n *\n * @public\n */\nexport function parseEnvAssignments(values: string[]): Record<string, string> {\n const env: Record<string, string> = {};\n for (const value of values) {\n const idx = value.indexOf(\"=\");\n if (idx <= 0) {\n throw new Error(`Invalid --env value \\\"${value}\\\". Use KEY=value.`);\n }\n const key = value.slice(0, idx).trim();\n const val = value.slice(idx + 1).trim();\n if (!key) {\n throw new Error(`Invalid --env value \\\"${value}\\\". Key cannot be empty.`);\n }\n env[key] = val;\n }\n return env;\n}\n\n/**\n * Extracts the version tag from an npm package specifier string.\n *\n * @remarks\n * Splits on the last `@` character to separate the package name from\n * the version tag. Returns undefined if no version tag is present or\n * the input is falsy.\n *\n * @param packageSpec - The npm package specifier, e.g., `\"@cleocode/cleo@1.2.0\"`\n * @returns The extracted version tag, or undefined if not present\n *\n * @example\n * ```typescript\n * const tag = extractVersionTag(\"@cleocode/cleo@1.2.0\");\n * // returns \"1.2.0\"\n * ```\n *\n * @public\n */\nexport function extractVersionTag(packageSpec?: string): string | undefined {\n if (!packageSpec) return undefined;\n const atIndex = packageSpec.lastIndexOf(\"@\");\n if (atIndex <= 0) return undefined;\n return packageSpec.slice(atIndex + 1);\n}\n\n/**\n * Checks whether a source string identifies a CLEO MCP installation.\n *\n * @remarks\n * Performs a case-insensitive comparison after trimming whitespace.\n * Returns true only when the source is exactly `\"cleo\"`.\n *\n * @param source - The source identifier string to check\n * @returns True if the source represents a CLEO installation\n *\n * @example\n * ```typescript\n * isCleoSource(\"cleo\"); // true\n * isCleoSource(\"Cleo\"); // true\n * isCleoSource(\"other\"); // false\n * ```\n *\n * @public\n */\nexport function isCleoSource(source: string): boolean {\n return source.trim().toLowerCase() === \"cleo\";\n}\n","/**\n * Shared lock file utilities\n *\n * Single source of truth for reading/writing the canonical CAAMP lock file path.\n * Both MCP and skills lock modules import from here.\n */\n\nimport { open, readFile, writeFile, mkdir, rm, rename, stat } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport type { CaampLockFile } from \"../types.js\";\nimport { AGENTS_HOME, LOCK_FILE_PATH } from \"./paths/agents.js\";\n\nconst LOCK_GUARD_PATH = `${LOCK_FILE_PATH}.lock`;\nconst STALE_LOCK_MS = 5_000;\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nasync function removeStaleLock(): Promise<boolean> {\n try {\n const info = await stat(LOCK_GUARD_PATH);\n if (Date.now() - info.mtimeMs > STALE_LOCK_MS) {\n await rm(LOCK_GUARD_PATH, { force: true });\n return true;\n }\n } catch {\n // Lock file doesn't exist or can't be stat'd — not stale\n }\n return false;\n}\n\nasync function acquireLockGuard(retries = 40, delayMs = 25): Promise<void> {\n await mkdir(AGENTS_HOME, { recursive: true });\n\n for (let attempt = 0; attempt < retries; attempt += 1) {\n try {\n const handle = await open(LOCK_GUARD_PATH, \"wx\");\n await handle.close();\n return;\n } catch (error) {\n if (!(error instanceof Error) || !(\"code\" in error) || (error as NodeJS.ErrnoException).code !== \"EEXIST\") {\n throw error;\n }\n // On first retry failure, check for stale lock from a crashed process\n if (attempt === 0) {\n const removed = await removeStaleLock();\n if (removed) continue;\n }\n await sleep(delayMs);\n }\n }\n\n throw new Error(\"Timed out waiting for lock file guard\");\n}\n\nasync function releaseLockGuard(): Promise<void> {\n await rm(LOCK_GUARD_PATH, { force: true });\n}\n\nasync function writeLockFileUnsafe(lock: CaampLockFile): Promise<void> {\n const tmpPath = `${LOCK_FILE_PATH}.tmp-${process.pid}-${Date.now()}`;\n await writeFile(tmpPath, JSON.stringify(lock, null, 2) + \"\\n\", \"utf-8\");\n await rename(tmpPath, LOCK_FILE_PATH);\n}\n\n/**\n * Read and parse the CAAMP lock file from disk.\n *\n * @remarks\n * Returns a default empty lock structure when the file does not exist or\n * cannot be parsed, ensuring callers always receive a valid object.\n *\n * @returns Parsed lock file contents\n *\n * @example\n * ```typescript\n * const lock = await readLockFile();\n * console.log(Object.keys(lock.mcpServers));\n * ```\n *\n * @public\n */\nexport async function readLockFile(): Promise<CaampLockFile> {\n try {\n if (!existsSync(LOCK_FILE_PATH)) {\n return { version: 1, skills: {}, mcpServers: {} };\n }\n const content = await readFile(LOCK_FILE_PATH, \"utf-8\");\n return JSON.parse(content) as CaampLockFile;\n } catch {\n return { version: 1, skills: {}, mcpServers: {} };\n }\n}\n\n/**\n * Write the lock file atomically under a process lock guard.\n *\n * @remarks\n * Uses a file-system lock guard to prevent concurrent writes from multiple\n * CAAMP processes. The write itself is atomic (write-to-tmp then rename).\n *\n * @param lock - Lock file data to persist\n *\n * @example\n * ```typescript\n * const lock = await readLockFile();\n * lock.mcpServers[\"my-server\"] = entry;\n * await writeLockFile(lock);\n * ```\n *\n * @public\n */\nexport async function writeLockFile(lock: CaampLockFile): Promise<void> {\n await acquireLockGuard();\n try {\n await writeLockFileUnsafe(lock);\n } finally {\n await releaseLockGuard();\n }\n}\n\n/**\n * Safely read-modify-write the lock file under a process lock guard.\n *\n * @remarks\n * Acquires an exclusive file-system lock, reads the current lock file, applies\n * the updater callback, writes the result atomically, and releases the lock.\n * The updater may mutate the lock object in place.\n *\n * @param updater - Callback that modifies the lock object (may be async)\n * @returns The updated lock file contents after the write\n *\n * @example\n * ```typescript\n * const updated = await updateLockFile((lock) => {\n * lock.mcpServers[\"new-server\"] = entry;\n * });\n * ```\n *\n * @public\n */\nexport async function updateLockFile(\n updater: (lock: CaampLockFile) => void | Promise<void>,\n): Promise<CaampLockFile> {\n await acquireLockGuard();\n try {\n const lock = await readLockFile();\n await updater(lock);\n await writeLockFileUnsafe(lock);\n return lock;\n } finally {\n await releaseLockGuard();\n }\n}\n","/**\n * MCP lock file management\n *\n * Tracks installed MCP servers with source and agent metadata.\n * Stored in the canonical CAAMP lock file (shared with skills lock).\n */\n\nimport type { LockEntry, SourceType } from \"../../types.js\";\nimport { readLockFile, updateLockFile } from \"../lock-utils.js\";\n\n/**\n * Read and parse the CAAMP lock file from the canonical lock path.\n *\n * Returns the full {@link CaampLockFile} structure. Creates a default lock file\n * if one does not exist.\n *\n * @remarks\n * The lock file is stored at the canonical CAAMP lock path and is shared\n * between MCP and skills tracking. If the file does not exist or cannot be\n * parsed, a default empty lock structure is returned.\n *\n * @returns The parsed lock file contents\n *\n * @example\n * ```typescript\n * const lock = await readLockFile();\n * console.log(Object.keys(lock.mcpServers));\n * ```\n *\n * @public\n */\nexport { readLockFile } from \"../lock-utils.js\";\n\n/**\n * Record an MCP server installation in the lock file.\n *\n * Creates or updates an entry in `lock.mcpServers`. If the server already exists,\n * the agent list is merged and `updatedAt` is refreshed while `installedAt` is preserved.\n *\n * @remarks\n * Uses an atomic read-modify-write pattern via `updateLockFile`. When updating\n * an existing entry, the agent list is deduplicated using a `Set` to prevent\n * duplicate provider IDs. The `installedAt` timestamp is preserved from the\n * original entry while `updatedAt` is always refreshed.\n *\n * @param serverName - Name/key of the MCP server\n * @param source - Original source string\n * @param sourceType - Classified source type\n * @param agents - Provider IDs the server was installed to\n * @param isGlobal - Whether this is a global installation\n * @param version - Optional version string for the installed package\n *\n * @example\n * ```typescript\n * await recordMcpInstall(\"filesystem\", \"@mcp/server-fs\", \"package\", [\"claude-code\"], true, \"1.0.0\");\n * ```\n *\n * @public\n */\nexport async function recordMcpInstall(\n serverName: string,\n source: string,\n sourceType: SourceType,\n agents: string[],\n isGlobal: boolean,\n version?: string,\n): Promise<void> {\n await updateLockFile((lock) => {\n const now = new Date().toISOString();\n const existing = lock.mcpServers[serverName];\n\n lock.mcpServers[serverName] = {\n name: serverName,\n scopedName: serverName,\n source,\n sourceType,\n version: version ?? existing?.version,\n installedAt: existing?.installedAt ?? now,\n updatedAt: now,\n agents: [...new Set([...(existing?.agents ?? []), ...agents])],\n canonicalPath: \"\",\n isGlobal,\n };\n });\n}\n\n/**\n * Remove an MCP server entry from the lock file.\n *\n * @remarks\n * Uses an atomic read-modify-write pattern. If the server name is not present\n * in the lock file, the file is not modified and `false` is returned.\n *\n * @param serverName - Name/key of the MCP server to remove\n * @returns `true` if the entry was found and removed, `false` if not found\n *\n * @example\n * ```typescript\n * const removed = await removeMcpFromLock(\"filesystem\");\n * if (removed) {\n * console.log(\"Server removed from lock file\");\n * }\n * ```\n *\n * @public\n */\nexport async function removeMcpFromLock(serverName: string): Promise<boolean> {\n let removed = false;\n await updateLockFile((lock) => {\n if (!(serverName in lock.mcpServers)) return;\n delete lock.mcpServers[serverName];\n removed = true;\n });\n return removed;\n}\n\n/**\n * Get all MCP servers tracked in the lock file.\n *\n * @remarks\n * Returns the `mcpServers` section of the lock file as a record. Each key\n * is a server name and each value contains installation metadata including\n * source, agents, timestamps, and scope.\n *\n * @returns Record of server name to lock entry\n *\n * @example\n * ```typescript\n * const servers = await getTrackedMcpServers();\n * for (const [name, entry] of Object.entries(servers)) {\n * console.log(`${name}: installed ${entry.installedAt}`);\n * }\n * ```\n *\n * @public\n */\nexport async function getTrackedMcpServers(): Promise<Record<string, LockEntry>> {\n const lock = await readLockFile();\n return lock.mcpServers;\n}\n\n/**\n * Save the last selected agent IDs to the lock file for UX persistence.\n *\n * Used to remember the user's agent selection between CLI invocations.\n *\n * @remarks\n * Persists the `lastSelectedAgents` field in the lock file so subsequent\n * CLI invocations can default to the same agent selection. This avoids\n * requiring the user to re-select agents each time.\n *\n * @param agents - Array of provider IDs to remember\n *\n * @example\n * ```typescript\n * await saveLastSelectedAgents([\"claude-code\", \"cursor\"]);\n * ```\n *\n * @public\n */\nexport async function saveLastSelectedAgents(agents: string[]): Promise<void> {\n await updateLockFile((lock) => {\n lock.lastSelectedAgents = agents;\n });\n}\n\n/**\n * Retrieve the last selected agent IDs from the lock file.\n *\n * @remarks\n * Returns the `lastSelectedAgents` field from the lock file, which is\n * set by {@link saveLastSelectedAgents}. Returns `undefined` if no\n * selection has been persisted yet.\n *\n * @returns Array of provider IDs, or `undefined` if none were saved\n *\n * @example\n * ```typescript\n * const agents = await getLastSelectedAgents();\n * // [\"claude-code\", \"cursor\"] or undefined\n * ```\n *\n * @public\n */\nexport async function getLastSelectedAgents(): Promise<string[] | undefined> {\n const lock = await readLockFile();\n return lock.lastSelectedAgents;\n}\n","/**\n * CLEO MCP lock reconciliation\n *\n * Infers lock metadata from live config entries and backfills\n * missing lock entries for CLEO servers installed before lock tracking.\n */\n\nimport type { LockEntry, McpServerEntry, SourceType } from \"../../types.js\";\nimport { getInstalledProviders } from \"../registry/detection.js\";\nimport {\n CLEO_MCP_NPM_PACKAGE,\n type CleoChannel,\n extractVersionTag,\n resolveChannelFromServerName,\n} from \"./cleo.js\";\nimport { getTrackedMcpServers, recordMcpInstall, removeMcpFromLock } from \"./lock.js\";\nimport { listMcpServers } from \"./reader.js\";\n\n/**\n * Lock metadata inferred from a live MCP config entry.\n *\n * @public\n */\nexport interface InferredLockData {\n /** The source string (package name, command, or path). */\n source: string;\n /** Classified source type. */\n sourceType: SourceType;\n /** Inferred version string, if extractable from the config. @defaultValue undefined */\n version: string | undefined;\n}\n\n/**\n * Infer lock metadata from a live MCP config entry.\n *\n * Determines source, sourceType, and version by inspecting the command and args\n * of an existing CLEO MCP server config entry.\n *\n * @remarks\n * The inference logic checks three patterns in order: (1) if any argument\n * contains the CLEO npm package name, it is classified as a `\"package\"` source\n * with the version extracted from the package specifier; (2) if the channel is\n * `\"dev\"` or the command contains path separators, it is classified as a\n * `\"command\"` source; (3) otherwise, the full command + args string is used as\n * a `\"command\"` source.\n *\n * @param config - The raw config object from the provider's config file\n * @param channel - The resolved CLEO channel (`\"stable\"`, `\"next\"`, or `\"dev\"`)\n * @returns Inferred lock metadata with source, sourceType, and optional version\n *\n * @example\n * ```typescript\n * const data = inferCleoLockData(\n * { command: \"npx\", args: [\"-y\", \"@cleocode/cleo-mcp@1.2.0\"] },\n * \"stable\",\n * );\n * // { source: \"@cleocode/cleo-mcp@1.2.0\", sourceType: \"package\", version: \"1.2.0\" }\n * ```\n *\n * @public\n */\nexport function inferCleoLockData(\n config: Record<string, unknown>,\n channel: CleoChannel,\n): InferredLockData {\n const command = typeof config.command === \"string\" ? config.command : \"\";\n const args = Array.isArray(config.args)\n ? config.args.filter((a): a is string => typeof a === \"string\")\n : [];\n\n // Check if any arg contains the CLEO npm package → package source\n const packageArg = args.find(\n (a) => a.includes(CLEO_MCP_NPM_PACKAGE),\n );\n\n if (packageArg) {\n const version = extractVersionTag(packageArg);\n return {\n source: packageArg,\n sourceType: \"package\",\n version,\n };\n }\n\n // Dev channel or path-based command → command source\n if (channel === \"dev\" || command.includes(\"/\") || command.includes(\"\\\\\")) {\n return {\n source: command,\n sourceType: \"command\",\n version: undefined,\n };\n }\n\n // Fallback: reconstruct from command + args\n const full = args.length > 0 ? `${command} ${args.join(\" \")}` : command;\n return {\n source: full || \"unknown\",\n sourceType: \"command\",\n version: undefined,\n };\n}\n\n/**\n * Options for the CLEO lock reconciliation process.\n *\n * @public\n */\nexport interface ReconcileOptions {\n /** Specific provider IDs to scan (if omitted, scans all installed). @defaultValue undefined */\n providerIds?: string[];\n /** Whether to scan all providers. @defaultValue undefined */\n all?: boolean;\n /** Whether to scan global-scope configs. @defaultValue undefined */\n global?: boolean;\n /** Whether to scan project-scope configs. @defaultValue undefined */\n project?: boolean;\n /** Whether to remove orphaned lock entries not found in any live config. @defaultValue undefined */\n prune?: boolean;\n /** If true, report changes without writing to the lock file. @defaultValue undefined */\n dryRun?: boolean;\n}\n\n/**\n * Result of a CLEO lock reconciliation operation.\n *\n * @public\n */\nexport interface ReconcileResult {\n /** Entries that were backfilled into the lock file. @defaultValue [] */\n backfilled: Array<{\n serverName: string;\n channel: CleoChannel;\n scope: \"project\" | \"global\";\n agents: string[];\n source: string;\n sourceType: SourceType;\n version: string | undefined;\n }>;\n /** Server names that were pruned from the lock file. */\n pruned: string[];\n /** Count of entries that were already tracked in the lock file. */\n alreadyTracked: number;\n /** Errors encountered during reconciliation. */\n errors: Array<{ message: string }>;\n}\n\n/**\n * Reconcile CLEO lock entries against live config.\n *\n * 1. Scans all providers x scopes for CLEO server entries\n * 2. Identifies entries not tracked in the lock file\n * 3. Backfills missing entries via recordMcpInstall\n * 4. Optionally prunes orphaned lock entries (in lock but not in any config)\n *\n * @remarks\n * This function bridges the gap between CLEO servers installed before lock\n * tracking was introduced and the current lock file state. It scans live\n * config files across all installed providers and requested scopes, infers\n * lock metadata from the config entries, and writes missing entries to the\n * lock file. When `prune` is enabled, it also removes lock entries for\n * CLEO servers that no longer appear in any live config.\n *\n * @param options - Reconciliation options controlling scope, providers, and behavior\n * @returns Reconciliation result with backfilled entries, pruned entries, and errors\n *\n * @example\n * ```typescript\n * const result = await reconcileCleoLock({ global: true, prune: true });\n * console.log(`Backfilled: ${result.backfilled.length}, Pruned: ${result.pruned.length}`);\n * ```\n *\n * @public\n */\nexport async function reconcileCleoLock(\n options: ReconcileOptions = {},\n): Promise<ReconcileResult> {\n const result: ReconcileResult = {\n backfilled: [],\n pruned: [],\n alreadyTracked: 0,\n errors: [],\n };\n\n const lockEntries = await getTrackedMcpServers();\n const providers = getInstalledProviders();\n\n // Filter providers if specific ones requested\n const targetProviders = options.providerIds?.length\n ? providers.filter((p) => options.providerIds!.includes(p.id))\n : providers;\n\n // Determine scopes to scan\n const scopes: Array<\"project\" | \"global\"> = [];\n if (options.global && !options.project) {\n scopes.push(\"global\");\n } else if (options.project && !options.global) {\n scopes.push(\"project\");\n } else {\n scopes.push(\"project\", \"global\");\n }\n\n // Group key: serverName + isGlobal → collected agents and config\n interface GroupEntry {\n serverName: string;\n channel: CleoChannel;\n scope: \"project\" | \"global\";\n agents: string[];\n config: Record<string, unknown>;\n }\n\n const groups = new Map<string, GroupEntry>();\n const liveCleoServerNames = new Set<string>();\n\n for (const scope of scopes) {\n for (const provider of targetProviders) {\n let entries: McpServerEntry[];\n try {\n entries = await listMcpServers(provider, scope);\n } catch {\n result.errors.push({\n message: `Failed to read config for ${provider.id} (${scope})`,\n });\n continue;\n }\n\n for (const entry of entries) {\n const channel = resolveChannelFromServerName(entry.name);\n if (!channel) continue;\n\n liveCleoServerNames.add(entry.name);\n\n const isGlobal = scope === \"global\";\n const groupKey = `${entry.name}:${isGlobal ? \"global\" : \"project\"}`;\n\n if (lockEntries[entry.name] !== undefined) {\n // Check if this specific provider is already tracked\n const existing = groups.get(groupKey);\n if (!existing) {\n result.alreadyTracked++;\n }\n continue;\n }\n\n const existing = groups.get(groupKey);\n if (existing) {\n if (!existing.agents.includes(provider.id)) {\n existing.agents.push(provider.id);\n }\n } else {\n groups.set(groupKey, {\n serverName: entry.name,\n channel,\n scope,\n agents: [provider.id],\n config: entry.config,\n });\n }\n }\n }\n }\n\n // Backfill untracked entries\n for (const group of groups.values()) {\n const inferred = inferCleoLockData(group.config, group.channel);\n\n if (!options.dryRun) {\n try {\n await recordMcpInstall(\n group.serverName,\n inferred.source,\n inferred.sourceType,\n group.agents,\n group.scope === \"global\",\n inferred.version,\n );\n } catch (err) {\n result.errors.push({\n message: `Failed to backfill ${group.serverName}: ${err instanceof Error ? err.message : String(err)}`,\n });\n continue;\n }\n }\n\n result.backfilled.push({\n serverName: group.serverName,\n channel: group.channel,\n scope: group.scope,\n agents: group.agents,\n source: inferred.source,\n sourceType: inferred.sourceType,\n version: inferred.version,\n });\n }\n\n // Prune orphaned lock entries (CLEO entries only)\n if (options.prune) {\n for (const [serverName] of Object.entries(lockEntries)) {\n const channel = resolveChannelFromServerName(serverName);\n if (!channel) continue; // Not a CLEO entry\n\n if (!liveCleoServerNames.has(serverName)) {\n if (!options.dryRun) {\n try {\n await removeMcpFromLock(serverName);\n } catch (err) {\n result.errors.push({\n message: `Failed to prune ${serverName}: ${err instanceof Error ? err.message : String(err)}`,\n });\n continue;\n }\n }\n result.pruned.push(serverName);\n }\n }\n }\n\n return result;\n}\n","/**\n * Source URL/path classifier\n *\n * Classifies inputs as remote URLs, npm packages, GitHub shorthand,\n * GitLab URLs, local paths, or shell commands.\n */\n\nimport type { ParsedSource, SourceType } from \"../../types.js\";\n\nconst GITHUB_SHORTHAND = /^([a-zA-Z0-9_.-]+)\\/([a-zA-Z0-9_.-]+)(?:\\/(.+))?$/;\nconst GITHUB_URL = /^https?:\\/\\/(?:www\\.)?github\\.com\\/([^/]+)\\/([^/]+)(?:\\/(?:tree|blob)\\/([^/]+)(?:\\/(.+))?)?/;\nconst GITLAB_URL = /^https?:\\/\\/(?:www\\.)?gitlab\\.com\\/([^/]+)\\/([^/]+)(?:\\/-\\/(?:tree|blob)\\/([^/]+)(?:\\/(.+))?)?/;\nconst HTTP_URL = /^https?:\\/\\//;\nconst NPM_SCOPED = /^@[a-zA-Z0-9_.-]+\\/[a-zA-Z0-9_.-]+$/;\nconst NPM_PACKAGE = /^[a-zA-Z0-9_.-]+$/;\nconst LIBRARY_SKILL = /^(@[a-zA-Z0-9_.-]+\\/[a-zA-Z0-9_.-]+|[a-zA-Z0-9_.-]+):([a-zA-Z0-9_.-]+)$/;\n\n/** Infer a display name from a source */\nfunction inferName(source: string, type: SourceType): string {\n if (type === \"library\") {\n const match = source.match(LIBRARY_SKILL);\n return match?.[2] ?? source;\n }\n\n if (type === \"remote\") {\n try {\n const url = new URL(source);\n // Extract brand from hostname: mcp.neon.tech -> neon\n const parts = url.hostname.split(\".\");\n if (parts.length >= 2) {\n const fallback = parts[0] ?? source;\n const secondLevel = parts[parts.length - 2] ?? fallback;\n const brand = parts.length === 3 ? secondLevel : fallback;\n if (brand !== \"www\" && brand !== \"api\" && brand !== \"mcp\") {\n return brand;\n }\n // Fall back to second-level domain\n return secondLevel;\n }\n return parts[0] ?? source;\n } catch {\n return source;\n }\n }\n\n if (type === \"package\") {\n // Strip common MCP prefixes/suffixes\n let name = source.replace(/^@[^/]+\\//, \"\"); // Remove scope\n name = name.replace(/^mcp-server-/, \"\");\n name = name.replace(/^server-/, \"\");\n name = name.replace(/-mcp$/, \"\");\n name = name.replace(/-server$/, \"\");\n return name;\n }\n\n if (type === \"github\" || type === \"gitlab\") {\n // Use repo name\n const match = source.match(/\\/([^/]+?)(?:\\.git)?$/);\n return match?.[1] ?? source;\n }\n\n if (type === \"local\") {\n // Extract directory basename from local path\n const normalized = source.replace(/\\\\/g, \"/\").replace(/\\/+$/, \"\");\n const lastSegment = normalized.split(\"/\").pop();\n return lastSegment ?? source;\n }\n\n if (type === \"command\") {\n // Extract first meaningful word\n const parts = source.split(/\\s+/);\n const command = parts.find((p) => !p.startsWith(\"-\") && p !== \"npx\" && p !== \"node\" && p !== \"python\" && p !== \"python3\");\n return command ?? parts[0] ?? source;\n }\n\n return source;\n}\n\n/**\n * Parse and classify a source string into a typed {@link ParsedSource}.\n *\n * @remarks\n * Supports GitHub URLs, GitLab URLs, GitHub shorthand (`owner/repo`),\n * HTTP URLs (remote MCP servers), npm package names, local paths, and\n * shell commands as a fallback.\n *\n * @param input - Raw source string to classify\n * @returns Parsed source with type, value, and inferred name\n *\n * @example\n * ```typescript\n * parseSource(\"owner/repo\");\n * // { type: \"github\", value: \"https://github.com/owner/repo\", inferredName: \"repo\", ... }\n *\n * parseSource(\"https://mcp.example.com/sse\");\n * // { type: \"remote\", value: \"https://mcp.example.com/sse\", inferredName: \"example\" }\n *\n * parseSource(\"@modelcontextprotocol/server-filesystem\");\n * // { type: \"package\", value: \"@modelcontextprotocol/server-filesystem\", inferredName: \"filesystem\" }\n * ```\n *\n * @public\n */\nexport function parseSource(input: string): ParsedSource {\n // GitHub URL\n const ghUrlMatch = input.match(GITHUB_URL);\n if (ghUrlMatch) {\n const owner = ghUrlMatch[1];\n const repo = ghUrlMatch[2];\n const path = ghUrlMatch[4];\n if (!owner || !repo) {\n return { type: \"command\", value: input, inferredName: inferName(input, \"command\") };\n }\n // Use last path segment as name if subpath provided, otherwise use repo name\n const inferredName = path ? path.split(\"/\").pop() ?? repo : repo;\n return {\n type: \"github\",\n value: input,\n inferredName,\n owner,\n repo,\n ref: ghUrlMatch[3],\n path,\n };\n }\n\n // GitLab URL\n const glUrlMatch = input.match(GITLAB_URL);\n if (glUrlMatch) {\n const owner = glUrlMatch[1];\n const repo = glUrlMatch[2];\n const path = glUrlMatch[4];\n if (!owner || !repo) {\n return { type: \"command\", value: input, inferredName: inferName(input, \"command\") };\n }\n // Use last path segment as name if subpath provided, otherwise use repo name\n const inferredName = path ? path.split(\"/\").pop() ?? repo : repo;\n return {\n type: \"gitlab\",\n value: input,\n inferredName,\n owner,\n repo,\n ref: glUrlMatch[3],\n path,\n };\n }\n\n // HTTP URL (non-GitHub/GitLab = remote MCP server)\n if (HTTP_URL.test(input)) {\n return {\n type: \"remote\",\n value: input,\n inferredName: inferName(input, \"remote\"),\n };\n }\n\n // Local path (check before GitHub shorthand since ./ and ../ match shorthand regex)\n if (input.startsWith(\"/\") || input.startsWith(\"./\") || input.startsWith(\"../\") || input.startsWith(\"~\")) {\n return {\n type: \"local\",\n value: input,\n inferredName: inferName(input, \"local\"),\n };\n }\n\n // GitHub shorthand: owner/repo or owner/repo/path\n const ghShorthand = input.match(GITHUB_SHORTHAND);\n if (ghShorthand && !NPM_SCOPED.test(input)) {\n const owner = ghShorthand[1];\n const repo = ghShorthand[2];\n const path = ghShorthand[3];\n if (!owner || !repo) {\n return { type: \"command\", value: input, inferredName: inferName(input, \"command\") };\n }\n // Use last path segment as name if subpath provided, otherwise use repo name\n const inferredName = path ? path.split(\"/\").pop() ?? repo : repo;\n return {\n type: \"github\",\n value: `https://github.com/${owner}/${repo}`,\n inferredName,\n owner,\n repo,\n path,\n };\n }\n\n // Library skill: package:skill or @scope/package:skill\n const libraryMatch = input.match(LIBRARY_SKILL);\n if (libraryMatch) {\n return {\n type: \"library\",\n value: input,\n inferredName: inferName(input, \"library\"),\n owner: libraryMatch[1], // This will be the package name, e.g. @cleocode/ct-skills\n repo: libraryMatch[2], // This will be the skill name, e.g. ct-research-agent\n };\n }\n\n // Scoped npm package: @scope/name\n if (NPM_SCOPED.test(input)) {\n return {\n type: \"package\",\n value: input,\n inferredName: inferName(input, \"package\"),\n };\n }\n\n // Simple npm package name (no spaces, no slashes)\n if (NPM_PACKAGE.test(input) && !input.includes(\" \")) {\n return {\n type: \"package\",\n value: input,\n inferredName: inferName(input, \"package\"),\n };\n }\n\n // Default: treat as command\n return {\n type: \"command\",\n value: input,\n inferredName: inferName(input, \"command\"),\n };\n}\n\n/**\n * Check if a source string looks like a marketplace scoped name (`@author/name`).\n *\n * @remarks\n * Matches strings in the `@scope/name` format commonly used by npm packages\n * and marketplace skill identifiers.\n *\n * @param input - Source string to check\n * @returns `true` if the input matches the `@scope/name` pattern\n *\n * @example\n * ```typescript\n * isMarketplaceScoped(\"@anthropic/my-skill\"); // true\n * isMarketplaceScoped(\"my-skill\"); // false\n * isMarketplaceScoped(\"owner/repo\"); // false\n * ```\n *\n * @public\n */\nexport function isMarketplaceScoped(input: string): boolean {\n return /^@[a-zA-Z0-9_.-]+\\/[a-zA-Z0-9_.-]+$/.test(input);\n}\n","/**\n * Default timeout in milliseconds for outbound HTTP requests.\n *\n * @public\n */\nexport const DEFAULT_FETCH_TIMEOUT_MS = 10_000;\n\ntype NetworkErrorKind = \"timeout\" | \"http\" | \"network\";\n\n/**\n * Structured error for network failures with categorized kind.\n *\n * @remarks\n * Carries the original URL, a classification of the failure (`\"timeout\"`,\n * `\"http\"`, or `\"network\"`), and an optional HTTP status code for `\"http\"`\n * failures.\n *\n * @public\n */\nexport class NetworkError extends Error {\n /** Classification of the failure. */\n kind: NetworkErrorKind;\n /** URL that was being fetched. */\n url: string;\n /** HTTP status code (only present for `\"http\"` kind). */\n status?: number;\n\n constructor(message: string, kind: NetworkErrorKind, url: string, status?: number) {\n super(message);\n this.name = \"NetworkError\";\n this.kind = kind;\n this.url = url;\n this.status = status;\n }\n}\n\nfunction isAbortError(error: unknown): boolean {\n return error instanceof Error && error.name === \"AbortError\";\n}\n\n/**\n * Fetch a URL with an automatic timeout via `AbortSignal.timeout`.\n *\n * @remarks\n * Wraps the native `fetch` API to provide consistent timeout and error\n * handling. Abort errors are translated into `NetworkError` with kind\n * `\"timeout\"`, and other failures become `\"network\"` errors.\n *\n * @param url - URL to fetch\n * @param init - Optional `RequestInit` options forwarded to `fetch`\n * @param timeoutMs - Timeout in milliseconds (defaults to {@link DEFAULT_FETCH_TIMEOUT_MS})\n * @returns The `Response` object from the fetch call\n * @throws {@link NetworkError} on timeout or network failure\n *\n * @example\n * ```typescript\n * const response = await fetchWithTimeout(\"https://api.example.com/data\", undefined, 5000);\n * ```\n *\n * @public\n */\nexport async function fetchWithTimeout(\n url: string,\n init?: RequestInit,\n timeoutMs = DEFAULT_FETCH_TIMEOUT_MS,\n): Promise<Response> {\n try {\n return await fetch(url, {\n ...init,\n signal: AbortSignal.timeout(timeoutMs),\n });\n } catch (error) {\n if (isAbortError(error)) {\n throw new NetworkError(`Request timed out after ${timeoutMs}ms`, \"timeout\", url);\n }\n throw new NetworkError(\"Network request failed\", \"network\", url);\n }\n}\n\n/**\n * Assert that a `Response` has an OK status, throwing on failure.\n *\n * @remarks\n * Convenience guard that throws a `NetworkError` with kind `\"http\"` when the\n * response status is outside the 200-299 range.\n *\n * @param response - Fetch `Response` to validate\n * @param url - Original request URL (included in the error)\n * @returns The same `Response` if status is OK\n * @throws {@link NetworkError} when `response.ok` is `false`\n *\n * @example\n * ```typescript\n * const res = await fetchWithTimeout(url);\n * ensureOkResponse(res, url);\n * ```\n *\n * @public\n */\nexport function ensureOkResponse(response: Response, url: string): Response {\n if (!response.ok) {\n throw new NetworkError(`Request failed with status ${response.status}`, \"http\", url, response.status);\n }\n return response;\n}\n\n/**\n * Format a network error into a user-friendly message string.\n *\n * @remarks\n * Recognizes `NetworkError` instances and produces kind-specific messages\n * (timeout, HTTP status, generic network). Falls back to `Error.message` or\n * `String()` for unknown error types.\n *\n * @param error - The caught error value\n * @returns Human-readable error description\n *\n * @example\n * ```typescript\n * try {\n * await fetchWithTimeout(url);\n * } catch (err) {\n * console.error(formatNetworkError(err));\n * }\n * ```\n *\n * @public\n */\nexport function formatNetworkError(error: unknown): string {\n if (error instanceof NetworkError) {\n if (error.kind === \"timeout\") {\n return \"Network request timed out. Please check your connection and try again.\";\n }\n if (error.kind === \"http\") {\n return `Marketplace request failed with HTTP ${error.status ?? \"unknown\"}. Please try again shortly.`;\n }\n return \"Network request failed. Please check your connection and try again.\";\n }\n\n if (error instanceof Error) return error.message;\n return String(error);\n}\n","/**\n * agentskills.in marketplace adapter\n *\n * Connects to the SkillsMP API for skill discovery.\n * GitHub is always the actual source for installation.\n */\n\nimport type { MarketplaceAdapter, MarketplaceResult, SearchOptions } from \"./types.js\";\nimport { ensureOkResponse, fetchWithTimeout } from \"../network/fetch.js\";\n\nconst API_BASE = \"https://www.agentskills.in/api/skills\";\n\ninterface ApiSkill {\n id: string;\n name: string;\n description: string;\n author: string;\n scopedName: string;\n stars: number;\n forks: number;\n githubUrl: string;\n repoFullName: string;\n path: string;\n category?: string;\n hasContent: boolean;\n}\n\ninterface ApiResponse {\n skills: ApiSkill[];\n total: number;\n limit: number;\n offset: number;\n}\n\ninterface ScopedNameParts {\n author: string;\n name: string;\n}\n\nfunction parseScopedName(value: string): ScopedNameParts | null {\n const match = value.match(/^@([^/]+)\\/([^/]+)$/);\n if (!match) return null;\n return {\n author: match[1]!,\n name: match[2]!,\n };\n}\n\nfunction toResult(skill: ApiSkill): MarketplaceResult {\n return {\n name: skill.name,\n scopedName: skill.scopedName,\n description: skill.description,\n author: skill.author,\n stars: skill.stars,\n githubUrl: skill.githubUrl,\n repoFullName: skill.repoFullName,\n path: skill.path,\n source: \"agentskills.in\",\n };\n}\n\n/**\n * Marketplace adapter for the agentskills.in API.\n *\n * @remarks\n * Implements the {@link MarketplaceAdapter} interface to search and retrieve\n * skills from the agentskills.in marketplace. GitHub remains the actual\n * source for skill installation — this adapter provides discovery only.\n *\n * @public\n */\nexport class SkillsMPAdapter implements MarketplaceAdapter {\n /** The marketplace identifier used in search results. */\n name = \"agentskills.in\";\n\n /**\n * Search for skills by query string.\n *\n * @param query - Search query to match against skill names and descriptions.\n * @param limit - Maximum number of results to return.\n * @returns Array of marketplace results sorted by stars.\n */\n async search(query: string, limit = 20): Promise<MarketplaceResult[]> {\n const params = new URLSearchParams({\n search: query,\n limit: String(limit),\n sortBy: \"stars\",\n });\n\n const url = `${API_BASE}?${params}`;\n const response = ensureOkResponse(await fetchWithTimeout(url), url);\n const data = (await response.json()) as ApiResponse;\n return data.skills.map(toResult);\n }\n\n /**\n * Look up a specific skill by its scoped name.\n *\n * @param scopedName - The scoped skill name (e.g. `\"@author/skill-name\"`).\n * @returns The matching marketplace result, or `null` if not found.\n */\n async getSkill(scopedName: string): Promise<MarketplaceResult | null> {\n const parts = parseScopedName(scopedName);\n const searchTerms = parts\n ? [parts.name, `${parts.author} ${parts.name}`, scopedName]\n : [scopedName];\n\n const seen = new Set<string>();\n for (const term of searchTerms) {\n if (seen.has(term)) continue;\n seen.add(term);\n\n const params = new URLSearchParams({\n search: term,\n limit: \"50\",\n sortBy: \"stars\",\n });\n\n const url = `${API_BASE}?${params}`;\n const response = ensureOkResponse(await fetchWithTimeout(url), url);\n const data = (await response.json()) as ApiResponse;\n const match = data.skills.find(\n (s) => s.scopedName === scopedName || `@${s.author}/${s.name}` === scopedName,\n );\n if (match) {\n return toResult(match);\n }\n }\n\n return null;\n }\n}\n","/**\n * skills.sh marketplace adapter\n *\n * Connects to the skills.sh API for skill discovery.\n * Uses the Vercel Skills model where GitHub is the actual source.\n */\n\nimport type { MarketplaceAdapter, MarketplaceResult } from \"./types.js\";\nimport { ensureOkResponse, fetchWithTimeout } from \"../network/fetch.js\";\n\nconst API_BASE = \"https://skills.sh/api\";\n\ninterface SkillsShResult {\n name: string;\n author: string;\n description: string;\n repo: string;\n stars?: number;\n url: string;\n}\n\ninterface SkillsShResponse {\n results: SkillsShResult[];\n total: number;\n}\n\nfunction toResult(skill: SkillsShResult): MarketplaceResult {\n return {\n name: skill.name,\n scopedName: `@${skill.author}/${skill.name}`,\n description: skill.description,\n author: skill.author,\n stars: skill.stars ?? 0,\n githubUrl: skill.url,\n repoFullName: skill.repo,\n path: \"\",\n source: \"skills.sh\",\n };\n}\n\n/**\n * Marketplace adapter for the skills.sh API.\n *\n * @remarks\n * Implements the {@link MarketplaceAdapter} interface to search and retrieve\n * skills from the skills.sh marketplace. Uses the Vercel Skills model where\n * GitHub is the actual source for installation.\n *\n * @public\n */\nexport class SkillsShAdapter implements MarketplaceAdapter {\n /** The marketplace identifier used in search results. */\n name = \"skills.sh\";\n\n /**\n * Search for skills by query string.\n *\n * @param query - Search query to match against skill names.\n * @param limit - Maximum number of results to return.\n * @returns Array of marketplace results.\n */\n async search(query: string, limit = 20): Promise<MarketplaceResult[]> {\n const params = new URLSearchParams({\n q: query,\n limit: String(limit),\n });\n\n const url = `${API_BASE}/search?${params}`;\n const response = ensureOkResponse(await fetchWithTimeout(url), url);\n const data = (await response.json()) as SkillsShResponse;\n return data.results.map(toResult);\n }\n\n /**\n * Look up a specific skill by its scoped name.\n *\n * @param scopedName - The scoped skill name (e.g. `\"@author/skill-name\"`).\n * @returns The matching marketplace result, or `null` if not found.\n */\n async getSkill(scopedName: string): Promise<MarketplaceResult | null> {\n const results = await this.search(scopedName, 5);\n return results.find((r) => r.scopedName === scopedName) ?? null;\n }\n}\n","/**\n * Unified marketplace client\n *\n * Aggregates results from multiple marketplace adapters,\n * deduplicates, and sorts by relevance.\n */\n\nimport type { MarketplaceAdapter, MarketplaceResult } from \"./types.js\";\nimport { SkillsMPAdapter } from \"./skillsmp.js\";\nimport { SkillsShAdapter } from \"./skillssh.js\";\n\n/**\n * Error thrown when all marketplace sources fail to respond.\n *\n * @remarks\n * Contains an array of per-adapter failure details so callers can report\n * which sources were unreachable and why.\n *\n * @public\n */\nexport class MarketplaceUnavailableError extends Error {\n /** Per-adapter failure messages. */\n details: string[];\n\n constructor(message: string, details: string[]) {\n super(message);\n this.name = \"MarketplaceUnavailableError\";\n this.details = details;\n }\n}\n\n/**\n * Unified marketplace client that aggregates results from multiple marketplace adapters.\n *\n * Queries all configured marketplaces in parallel, deduplicates results by scoped name,\n * and sorts by star count.\n *\n * @remarks\n * Default adapters query agentskills.in and skills.sh. Custom adapters can\n * be injected via the constructor for testing or additional sources.\n *\n * @example\n * ```typescript\n * const client = new MarketplaceClient();\n * const results = await client.search(\"filesystem\");\n * for (const r of results) {\n * console.log(`${r.scopedName} (${r.stars} stars)`);\n * }\n * ```\n *\n * @public\n */\nexport class MarketplaceClient {\n /** Configured marketplace adapters. */\n private adapters: MarketplaceAdapter[];\n\n /**\n * Create a new marketplace client.\n *\n * @param adapters - Custom marketplace adapters (defaults to agentskills.in and skills.sh)\n *\n * @example\n * ```typescript\n * // Use default adapters\n * const client = new MarketplaceClient();\n *\n * // Use custom adapters\n * const client = new MarketplaceClient([myAdapter]);\n * ```\n */\n constructor(adapters?: MarketplaceAdapter[]) {\n this.adapters = adapters ?? [\n new SkillsMPAdapter(),\n new SkillsShAdapter(),\n ];\n }\n\n /**\n * Search all marketplaces and return deduplicated, sorted results.\n *\n * Queries all adapters in parallel and deduplicates by `scopedName`,\n * keeping the entry with the highest star count. Results are sorted by\n * stars descending.\n *\n * @param query - Search query string\n * @param limit - Maximum number of results to return (default: 20)\n * @returns Deduplicated and sorted marketplace results\n *\n * @example\n * ```typescript\n * const results = await client.search(\"code review\", 10);\n * ```\n */\n async search(query: string, limit = 20): Promise<MarketplaceResult[]> {\n const settled = await Promise.allSettled(this.adapters.map((adapter) => adapter.search(query, limit)));\n\n const flat: MarketplaceResult[] = [];\n const failures: string[] = [];\n\n for (const [index, result] of settled.entries()) {\n const adapterName = this.adapters[index]?.name ?? \"unknown\";\n\n if (result.status === \"fulfilled\") {\n flat.push(...result.value);\n } else {\n const reason = result.reason instanceof Error ? result.reason.message : String(result.reason);\n failures.push(`${adapterName}: ${reason}`);\n }\n }\n\n if (flat.length === 0 && failures.length > 0) {\n throw new MarketplaceUnavailableError(\"All marketplace sources failed.\", failures);\n }\n\n // Deduplicate by scopedName, keeping higher star count\n const seen = new Map<string, MarketplaceResult>();\n for (const result of flat) {\n const existing = seen.get(result.scopedName);\n if (!existing || result.stars > existing.stars) {\n seen.set(result.scopedName, result);\n }\n }\n\n // Sort by stars descending\n const deduplicated = Array.from(seen.values());\n deduplicated.sort((a, b) => b.stars - a.stars);\n\n return deduplicated.slice(0, limit);\n }\n\n /**\n * Get a specific skill by its scoped name from any marketplace.\n *\n * Tries each adapter in order and returns the first match.\n *\n * @param scopedName - Scoped skill name (e.g. `\"@author/my-skill\"`)\n * @returns The marketplace result, or `null` if not found in any marketplace\n *\n * @example\n * ```typescript\n * const skill = await client.getSkill(\"@anthropic/memory\");\n * ```\n */\n async getSkill(scopedName: string): Promise<MarketplaceResult | null> {\n const failures: string[] = [];\n\n for (const adapter of this.adapters) {\n try {\n const result = await adapter.getSkill(scopedName);\n if (result) return result;\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error);\n failures.push(`${adapter.name}: ${reason}`);\n }\n }\n\n if (failures.length === this.adapters.length && this.adapters.length > 0) {\n throw new MarketplaceUnavailableError(\"All marketplace sources failed.\", failures);\n }\n\n return null;\n }\n}\n","/**\n * Library loader - loads a SkillLibrary from a directory or module.\n *\n * Two strategies:\n * 1. loadLibraryFromModule() - for libraries with an index.js exporting SkillLibrary\n * 2. buildLibraryFromFiles() - for plain directories with the right file structure\n */\n\nimport { createRequire } from \"node:module\";\nimport { existsSync, readdirSync, readFileSync } from \"node:fs\";\nimport { basename, dirname, join } from \"node:path\";\nimport type {\n SkillLibrary,\n SkillLibraryEntry,\n SkillLibraryManifest,\n SkillLibraryProfile,\n SkillLibraryDispatchMatrix,\n SkillLibraryValidationResult,\n SkillLibraryValidationIssue,\n} from \"./skill-library.js\";\n\nconst require = createRequire(import.meta.url);\n\n/**\n * Load a SkillLibrary from a module (index.js) at the given root directory.\n *\n * @remarks\n * Uses `createRequire()` for CJS modules or dynamic `import()` for ESM.\n * Validates that the loaded module implements the SkillLibrary interface\n * by checking for required properties and methods.\n *\n * @param root - Absolute path to the library root (must contain index.js or package.json with main)\n * @returns A validated SkillLibrary instance\n * @throws If the module cannot be loaded or does not implement SkillLibrary\n *\n * @example\n * ```typescript\n * const library = loadLibraryFromModule(\"/home/user/.agents/libraries/ct-skills\");\n * console.log(`Loaded v${library.version} with ${library.listSkills().length} skills`);\n * ```\n *\n * @public\n */\nexport function loadLibraryFromModule(root: string): SkillLibrary {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let mod: any;\n\n try {\n mod = require(root);\n } catch {\n throw new Error(`Failed to load skill library module from ${root}`);\n }\n\n // Validate required properties\n const requiredMethods = [\n \"listSkills\", \"getSkill\", \"getSkillPath\", \"getSkillDir\", \"readSkillContent\",\n \"getCoreSkills\", \"getSkillsByCategory\", \"getSkillDependencies\", \"resolveDependencyTree\",\n \"listProfiles\", \"getProfile\", \"resolveProfile\",\n \"listSharedResources\", \"getSharedResourcePath\", \"readSharedResource\",\n \"listProtocols\", \"getProtocolPath\", \"readProtocol\",\n \"validateSkillFrontmatter\", \"validateAll\", \"getDispatchMatrix\",\n ];\n\n for (const method of requiredMethods) {\n if (typeof mod[method] !== \"function\") {\n throw new Error(\n `Skill library at ${root} does not implement required method: ${method}`,\n );\n }\n }\n\n if (!mod.version || typeof mod.version !== \"string\") {\n throw new Error(`Skill library at ${root} is missing 'version' property`);\n }\n\n if (!mod.libraryRoot || typeof mod.libraryRoot !== \"string\") {\n throw new Error(`Skill library at ${root} is missing 'libraryRoot' property`);\n }\n\n return mod as SkillLibrary;\n}\n\n/**\n * Build a SkillLibrary from raw files in a directory.\n *\n * @remarks\n * Constructs a full SkillLibrary implementation by reading:\n * - `skills.json` for catalog entries\n * - `skills/manifest.json` for dispatch matrix\n * - `profiles/*.json` for profile definitions\n * - `skills/<name>/SKILL.md` for skill content\n * - `skills/_shared/*.md` for shared resources\n * - `protocols/*.md` or `skills/protocols/*.md` for protocol files\n *\n * @param root - Absolute path to the library root directory\n * @returns A SkillLibrary instance backed by filesystem reads\n * @throws If skills.json is not found at the root\n *\n * @example\n * ```typescript\n * const library = buildLibraryFromFiles(\"/home/user/.agents/libraries/ct-skills\");\n * const coreSkills = library.getCoreSkills();\n * console.log(`Core skills: ${coreSkills.map(s => s.name).join(\", \")}`);\n * ```\n *\n * @public\n */\nexport function buildLibraryFromFiles(root: string): SkillLibrary {\n const catalogPath = join(root, \"skills.json\");\n if (!existsSync(catalogPath)) {\n throw new Error(`No skills.json found at ${root}`);\n }\n\n const catalogData = JSON.parse(readFileSync(catalogPath, \"utf-8\"));\n const entries: SkillLibraryEntry[] = catalogData.skills ?? [];\n const version: string = catalogData.version ?? \"0.0.0\";\n\n // Load manifest\n const manifestPath = join(root, \"skills\", \"manifest.json\");\n let manifest: SkillLibraryManifest;\n if (existsSync(manifestPath)) {\n manifest = JSON.parse(readFileSync(manifestPath, \"utf-8\"));\n } else {\n manifest = {\n $schema: \"\",\n _meta: {},\n dispatch_matrix: { by_task_type: {}, by_keyword: {}, by_protocol: {} },\n skills: [],\n };\n }\n\n // Load profiles\n const profilesDir = join(root, \"profiles\");\n const profiles = new Map<string, SkillLibraryProfile>();\n if (existsSync(profilesDir)) {\n for (const file of readdirSync(profilesDir)) {\n if (!file.endsWith(\".json\")) continue;\n try {\n const profile: SkillLibraryProfile = JSON.parse(\n readFileSync(join(profilesDir, file), \"utf-8\"),\n );\n profiles.set(profile.name, profile);\n } catch {\n // Skip invalid profiles\n }\n }\n }\n\n // Build skill lookup map\n const skillMap = new Map<string, SkillLibraryEntry>();\n for (const entry of entries) {\n skillMap.set(entry.name, entry);\n }\n\n // ── Helper functions ──────────────────────────────────────────────\n\n function getSkillDir(name: string): string {\n const entry = skillMap.get(name);\n if (entry) {\n return dirname(join(root, entry.path));\n }\n return join(root, \"skills\", name);\n }\n\n function resolveDeps(names: string[], visited = new Set<string>()): string[] {\n const result: string[] = [];\n for (const name of names) {\n if (visited.has(name)) continue;\n visited.add(name);\n\n const entry = skillMap.get(name);\n if (entry && entry.dependencies.length > 0) {\n result.push(...resolveDeps(entry.dependencies, visited));\n }\n result.push(name);\n }\n return result;\n }\n\n function resolveProfileByName(name: string, visited = new Set<string>()): string[] {\n if (visited.has(name)) return [];\n visited.add(name);\n\n const profile = profiles.get(name);\n if (!profile) return [];\n\n let skills: string[] = [];\n if (profile.extends) {\n skills = resolveProfileByName(profile.extends, visited);\n }\n skills.push(...profile.skills);\n\n // Resolve dependencies for all skills\n return resolveDeps([...new Set(skills)]);\n }\n\n function discoverFiles(dir: string, ext: string): string[] {\n if (!existsSync(dir)) return [];\n return readdirSync(dir)\n .filter(f => f.endsWith(ext))\n .map(f => basename(f, ext));\n }\n\n // ── Build the library object ──────────────────────────────────────\n\n const library: SkillLibrary = {\n version,\n libraryRoot: root,\n skills: entries,\n manifest,\n\n listSkills(): string[] {\n return entries.map(e => e.name);\n },\n\n getSkill(name: string): SkillLibraryEntry | undefined {\n return skillMap.get(name);\n },\n\n getSkillPath(name: string): string {\n const entry = skillMap.get(name);\n if (entry) {\n return join(root, entry.path);\n }\n return join(root, \"skills\", name, \"SKILL.md\");\n },\n\n getSkillDir,\n\n readSkillContent(name: string): string {\n const skillPath = library.getSkillPath(name);\n if (!existsSync(skillPath)) {\n throw new Error(`Skill content not found: ${skillPath}`);\n }\n return readFileSync(skillPath, \"utf-8\");\n },\n\n getCoreSkills(): SkillLibraryEntry[] {\n return entries.filter(e => e.core);\n },\n\n getSkillsByCategory(category: SkillLibraryEntry[\"category\"]): SkillLibraryEntry[] {\n return entries.filter(e => e.category === category);\n },\n\n getSkillDependencies(name: string): string[] {\n return skillMap.get(name)?.dependencies ?? [];\n },\n\n resolveDependencyTree(names: string[]): string[] {\n return resolveDeps(names);\n },\n\n listProfiles(): string[] {\n return [...profiles.keys()];\n },\n\n getProfile(name: string): SkillLibraryProfile | undefined {\n return profiles.get(name);\n },\n\n resolveProfile(name: string): string[] {\n return resolveProfileByName(name);\n },\n\n listSharedResources(): string[] {\n return discoverFiles(join(root, \"skills\", \"_shared\"), \".md\");\n },\n\n getSharedResourcePath(name: string): string | undefined {\n const resourcePath = join(root, \"skills\", \"_shared\", `${name}.md`);\n return existsSync(resourcePath) ? resourcePath : undefined;\n },\n\n readSharedResource(name: string): string | undefined {\n const resourcePath = library.getSharedResourcePath(name);\n if (!resourcePath) return undefined;\n return readFileSync(resourcePath, \"utf-8\");\n },\n\n listProtocols(): string[] {\n // Check root protocols/ first (ct-skills layout), fall back to skills/protocols/\n const rootProtocols = discoverFiles(join(root, \"protocols\"), \".md\");\n if (rootProtocols.length > 0) return rootProtocols;\n return discoverFiles(join(root, \"skills\", \"protocols\"), \".md\");\n },\n\n getProtocolPath(name: string): string | undefined {\n // Check root protocols/ first, fall back to skills/protocols/\n const rootPath = join(root, \"protocols\", `${name}.md`);\n if (existsSync(rootPath)) return rootPath;\n const skillsPath = join(root, \"skills\", \"protocols\", `${name}.md`);\n return existsSync(skillsPath) ? skillsPath : undefined;\n },\n\n readProtocol(name: string): string | undefined {\n const protocolPath = library.getProtocolPath(name);\n if (!protocolPath) return undefined;\n return readFileSync(protocolPath, \"utf-8\");\n },\n\n validateSkillFrontmatter(name: string): SkillLibraryValidationResult {\n const entry = skillMap.get(name);\n if (!entry) {\n return {\n valid: false,\n issues: [{ level: \"error\", field: \"name\", message: `Skill not found: ${name}` }],\n };\n }\n\n const issues: SkillLibraryValidationIssue[] = [];\n\n if (!entry.name) {\n issues.push({ level: \"error\", field: \"name\", message: \"Missing name\" });\n }\n if (!entry.description) {\n issues.push({ level: \"error\", field: \"description\", message: \"Missing description\" });\n }\n if (!entry.version) {\n issues.push({ level: \"warn\", field: \"version\", message: \"Missing version\" });\n }\n\n // Check SKILL.md exists\n const skillPath = join(root, entry.path);\n if (!existsSync(skillPath)) {\n issues.push({ level: \"error\", field: \"path\", message: `SKILL.md not found at ${entry.path}` });\n }\n\n return {\n valid: !issues.some(i => i.level === \"error\"),\n issues,\n };\n },\n\n validateAll(): Map<string, SkillLibraryValidationResult> {\n const results = new Map<string, SkillLibraryValidationResult>();\n for (const entry of entries) {\n results.set(entry.name, library.validateSkillFrontmatter(entry.name));\n }\n return results;\n },\n\n getDispatchMatrix(): SkillLibraryDispatchMatrix {\n return manifest.dispatch_matrix;\n },\n };\n\n return library;\n}\n","/**\n * Skill catalog - registry pattern for pluggable skill libraries.\n *\n * Projects MUST register their skill library via registerSkillLibrary() or\n * registerSkillLibraryFromPath(). CAAMP no longer auto-discovers from\n * ~/.agents/skill-library/ - explicit registration is required.\n *\n * All public functions delegate to the registered SkillLibrary instance.\n */\n\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { buildLibraryFromFiles, loadLibraryFromModule } from \"./library-loader.js\";\nimport type {\n SkillLibrary,\n SkillLibraryEntry,\n SkillLibraryManifest,\n SkillLibraryProfile,\n SkillLibraryDispatchMatrix,\n SkillLibraryValidationResult,\n} from \"./skill-library.js\";\n\n// ── Registry ────────────────────────────────────────────────────────\n\nlet _library: SkillLibrary | null = null;\n\n/**\n * Registers a SkillLibrary instance directly as the active catalog.\n *\n * @remarks\n * Replaces any previously registered library. This is the programmatic\n * registration path for when you already have a constructed SkillLibrary\n * instance. For path-based registration, use {@link registerSkillLibraryFromPath}.\n *\n * @param library - A SkillLibrary implementation to use as the catalog\n *\n * @example\n * ```typescript\n * const library = buildLibraryFromFiles(\"/path/to/skills\");\n * registerSkillLibrary(library);\n * ```\n *\n * @public\n */\nexport function registerSkillLibrary(library: SkillLibrary): void {\n _library = library;\n}\n\n/**\n * Registers a skill library by loading it from a directory path.\n *\n * @remarks\n * Tries two strategies in order: first attempts module-based loading if\n * the directory contains an `index.js`, then falls back to file-based\n * loading from raw files like `skills.json`. Replaces any previously\n * registered library on success.\n *\n * @param root - Absolute path to the skill library root directory\n * @throws Error if the library cannot be loaded from the given path\n *\n * @example\n * ```typescript\n * registerSkillLibraryFromPath(\"/home/user/.agents/skill-library\");\n * const skills = listSkills();\n * ```\n *\n * @public\n */\nexport function registerSkillLibraryFromPath(root: string): void {\n // Try module-based loading first (has index.js)\n const indexPath = join(root, \"index.js\");\n if (existsSync(indexPath)) {\n _library = loadLibraryFromModule(root);\n return;\n }\n\n // Fall back to file-based loading (has skills.json)\n _library = buildLibraryFromFiles(root);\n}\n\n/**\n * Clears the registered skill library instance.\n *\n * @remarks\n * Resets the internal library reference to null. Primarily intended for\n * test isolation to ensure a clean state between test cases.\n *\n * @example\n * ```typescript\n * clearRegisteredLibrary();\n * // isCatalogAvailable() will now return false unless auto-discovery succeeds\n * ```\n *\n * @public\n */\nexport function clearRegisteredLibrary(): void {\n _library = null;\n}\n\n// ── Auto-discovery ──────────────────────────────────────────────────\n\n/**\n * Attempt to discover a skill library from well-known locations.\n *\n * Discovery order:\n * 1. CAAMP_SKILL_LIBRARY env var (path to library root)\n */\nfunction discoverLibrary(): SkillLibrary | null {\n // 1. Environment variable\n const envPath = process.env[\"CAAMP_SKILL_LIBRARY\"];\n if (envPath && existsSync(envPath)) {\n try {\n const indexPath = join(envPath, \"index.js\");\n if (existsSync(indexPath)) {\n return loadLibraryFromModule(envPath);\n }\n if (existsSync(join(envPath, \"skills.json\"))) {\n return buildLibraryFromFiles(envPath);\n }\n } catch {\n // Fall through\n }\n }\n\n return null;\n}\n\n// ── Internal accessor ───────────────────────────────────────────────\n\nfunction getLibrary(): SkillLibrary {\n if (!_library) {\n const discovered = discoverLibrary();\n if (discovered) {\n _library = discovered;\n }\n }\n\n if (!_library) {\n throw new Error(\n \"No skill library registered. Register one with registerSkillLibraryFromPath() \" +\n \"or set the CAAMP_SKILL_LIBRARY environment variable.\",\n );\n }\n\n return _library;\n}\n\n// ── Public API (delegates to registered library) ────────────────────\n\n/**\n * Checks whether a skill library is available for use.\n *\n * @remarks\n * Returns true if a library has been explicitly registered or can be\n * auto-discovered via the `CAAMP_SKILL_LIBRARY` environment variable.\n * Does not throw on failure; catches any errors from discovery and\n * returns false instead.\n *\n * @returns True if a skill library is registered or discoverable, false otherwise\n *\n * @example\n * ```typescript\n * if (isCatalogAvailable()) {\n * const skills = listSkills();\n * }\n * ```\n *\n * @public\n */\nexport function isCatalogAvailable(): boolean {\n try {\n getLibrary();\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Returns all skill entries from the catalog.\n *\n * @remarks\n * Delegates to the registered skill library's `skills` property.\n * Throws if no library is registered or discoverable.\n *\n * @returns An array of all skill library entries\n *\n * @example\n * ```typescript\n * const allSkills = getSkills();\n * console.log(`Found ${allSkills.length} skills`);\n * ```\n *\n * @public\n */\nexport function getSkills(): SkillLibraryEntry[] {\n return getLibrary().skills;\n}\n\n/**\n * Returns the parsed skill library manifest.\n *\n * @remarks\n * The manifest contains library metadata, version info, and the dispatch\n * matrix. Delegates to the registered library instance.\n *\n * @returns The skill library manifest object\n *\n * @example\n * ```typescript\n * const manifest = getManifest();\n * console.log(manifest.version);\n * ```\n *\n * @public\n */\nexport function getManifest(): SkillLibraryManifest {\n return getLibrary().manifest;\n}\n\n/**\n * Lists all available skill names in the catalog.\n *\n * @remarks\n * Returns the names of all registered skills. Useful for discovery\n * and enumeration without loading full skill metadata.\n *\n * @returns An array of skill name strings\n *\n * @example\n * ```typescript\n * const names = listSkills();\n * // e.g., [\"ct-orchestrator\", \"ct-dev-workflow\", \"ct-validator\"]\n * ```\n *\n * @public\n */\nexport function listSkills(): string[] {\n return getLibrary().listSkills();\n}\n\n/**\n * Gets skill metadata by name from the catalog.\n *\n * @remarks\n * Looks up a skill by its unique name in the registered library.\n * Returns undefined if no skill with the given name exists.\n *\n * @param name - The unique skill name to look up\n * @returns The skill entry if found, or undefined\n *\n * @example\n * ```typescript\n * const skill = getSkill(\"ct-orchestrator\");\n * if (skill) {\n * console.log(skill.category);\n * }\n * ```\n *\n * @public\n */\nexport function getSkill(name: string): SkillLibraryEntry | undefined {\n return getLibrary().getSkill(name);\n}\n\n/**\n * Resolves the absolute path to a skill's SKILL.md file.\n *\n * @remarks\n * Combines the library root with the skill's relative path to produce\n * the absolute filesystem path to the SKILL.md file.\n *\n * @param name - The unique skill name to resolve\n * @returns The absolute path to the skill's SKILL.md file\n *\n * @example\n * ```typescript\n * const path = getSkillPath(\"ct-orchestrator\");\n * // e.g., \"/home/user/.agents/skill-library/skills/ct-orchestrator/SKILL.md\"\n * ```\n *\n * @public\n */\nexport function getSkillPath(name: string): string {\n return getLibrary().getSkillPath(name);\n}\n\n/**\n * Resolves the absolute path to a skill's directory.\n *\n * @remarks\n * Returns the parent directory of the skill's SKILL.md file,\n * which may contain additional resources referenced by the skill.\n *\n * @param name - The unique skill name to resolve\n * @returns The absolute path to the skill's directory\n *\n * @example\n * ```typescript\n * const dir = getSkillDir(\"ct-orchestrator\");\n * // e.g., \"/home/user/.agents/skill-library/skills/ct-orchestrator\"\n * ```\n *\n * @public\n */\nexport function getSkillDir(name: string): string {\n return getLibrary().getSkillDir(name);\n}\n\n/**\n * Reads a skill's SKILL.md content as a string.\n *\n * @remarks\n * Reads the full content of the skill's SKILL.md file from disk.\n * Throws if the skill does not exist or the file cannot be read.\n *\n * @param name - The unique skill name to read\n * @returns The full text content of the skill's SKILL.md file\n *\n * @example\n * ```typescript\n * const content = readSkillContent(\"ct-orchestrator\");\n * console.log(content.substring(0, 100));\n * ```\n *\n * @public\n */\nexport function readSkillContent(name: string): string {\n return getLibrary().readSkillContent(name);\n}\n\n/**\n * Returns all skills marked as core in the catalog.\n *\n * @remarks\n * Filters the skill list to only include entries where `core` is true.\n * Core skills are foundational capabilities that most agents need.\n *\n * @returns An array of core skill entries\n *\n * @example\n * ```typescript\n * const coreSkills = getCoreSkills();\n * console.log(`${coreSkills.length} core skills available`);\n * ```\n *\n * @public\n */\nexport function getCoreSkills(): SkillLibraryEntry[] {\n return getLibrary().getCoreSkills();\n}\n\n/**\n * Returns skills filtered by category.\n *\n * @remarks\n * Filters the skill list to only include entries matching the specified\n * category. Categories organize skills by their functional purpose.\n *\n * @param category - The category to filter by\n * @returns An array of skill entries in the specified category\n *\n * @example\n * ```typescript\n * const planningSkills = getSkillsByCategory(\"planning\");\n * ```\n *\n * @public\n */\nexport function getSkillsByCategory(category: SkillLibraryEntry[\"category\"]): SkillLibraryEntry[] {\n return getLibrary().getSkillsByCategory(category);\n}\n\n/**\n * Gets the direct dependency names for a skill.\n *\n * @remarks\n * Returns only the immediate dependencies, not transitive ones.\n * Use {@link resolveDependencyTree} for the full transitive closure.\n *\n * @param name - The unique skill name to query dependencies for\n * @returns An array of direct dependency skill names\n *\n * @example\n * ```typescript\n * const deps = getSkillDependencies(\"ct-task-executor\");\n * // e.g., [\"ct-orchestrator\"]\n * ```\n *\n * @public\n */\nexport function getSkillDependencies(name: string): string[] {\n return getLibrary().getSkillDependencies(name);\n}\n\n/**\n * Resolves the full dependency tree for a set of skill names.\n *\n * @remarks\n * Performs transitive dependency resolution, returning all skills that\n * must be installed for the given set of skills to function correctly.\n * Handles circular dependencies gracefully.\n *\n * @param names - The skill names to resolve dependencies for\n * @returns A deduplicated array of all required skill names including transitive dependencies\n *\n * @example\n * ```typescript\n * const allDeps = resolveDependencyTree([\"ct-task-executor\", \"ct-validator\"]);\n * // includes all transitive dependencies\n * ```\n *\n * @public\n */\nexport function resolveDependencyTree(names: string[]): string[] {\n return getLibrary().resolveDependencyTree(names);\n}\n\n/**\n * Lists all available profile names in the catalog.\n *\n * @remarks\n * Profiles are named collections of skills that can be installed together.\n * Returns just the profile names; use {@link getProfile} for full details.\n *\n * @returns An array of profile name strings\n *\n * @example\n * ```typescript\n * const profiles = listProfiles();\n * // e.g., [\"default\", \"minimal\", \"full\"]\n * ```\n *\n * @public\n */\nexport function listProfiles(): string[] {\n return getLibrary().listProfiles();\n}\n\n/**\n * Gets a profile definition by name from the catalog.\n *\n * @remarks\n * Returns the full profile definition including its skill list and\n * any `extends` references. Returns undefined if no profile with\n * the given name exists.\n *\n * @param name - The unique profile name to look up\n * @returns The profile definition if found, or undefined\n *\n * @example\n * ```typescript\n * const profile = getProfile(\"default\");\n * if (profile) {\n * console.log(profile.skills);\n * }\n * ```\n *\n * @public\n */\nexport function getProfile(name: string): SkillLibraryProfile | undefined {\n return getLibrary().getProfile(name);\n}\n\n/**\n * Resolves a profile to its full skill list including inherited skills.\n *\n * @remarks\n * Follows `extends` chains and resolves all transitive dependencies,\n * returning the complete list of skills needed for the profile.\n *\n * @param name - The profile name to resolve\n * @returns A deduplicated array of all skill names required by the profile\n *\n * @example\n * ```typescript\n * const skills = resolveProfile(\"default\");\n * // includes all skills from extended profiles and their dependencies\n * ```\n *\n * @public\n */\nexport function resolveProfile(name: string): string[] {\n return getLibrary().resolveProfile(name);\n}\n\n/**\n * Lists all available shared resource names in the catalog.\n *\n * @remarks\n * Shared resources are files in the `_shared` directory that multiple\n * skills can reference. Returns just the resource names.\n *\n * @returns An array of shared resource name strings\n *\n * @example\n * ```typescript\n * const resources = listSharedResources();\n * // e.g., [\"testing-framework-config.md\", \"error-handling.md\"]\n * ```\n *\n * @public\n */\nexport function listSharedResources(): string[] {\n return getLibrary().listSharedResources();\n}\n\n/**\n * Gets the absolute path to a shared resource file.\n *\n * @remarks\n * Resolves the filesystem path for a shared resource by name.\n * Returns undefined if the resource does not exist.\n *\n * @param name - The shared resource name to resolve\n * @returns The absolute path to the resource file, or undefined if not found\n *\n * @example\n * ```typescript\n * const path = getSharedResourcePath(\"testing-framework-config.md\");\n * ```\n *\n * @public\n */\nexport function getSharedResourcePath(name: string): string | undefined {\n return getLibrary().getSharedResourcePath(name);\n}\n\n/**\n * Reads a shared resource file's content as a string.\n *\n * @remarks\n * Reads the full content of a shared resource file from disk.\n * Returns undefined if the resource does not exist.\n *\n * @param name - The shared resource name to read\n * @returns The text content of the resource, or undefined if not found\n *\n * @example\n * ```typescript\n * const content = readSharedResource(\"testing-framework-config.md\");\n * if (content) {\n * console.log(content);\n * }\n * ```\n *\n * @public\n */\nexport function readSharedResource(name: string): string | undefined {\n return getLibrary().readSharedResource(name);\n}\n\n/**\n * Lists all available protocol names in the catalog.\n *\n * @remarks\n * Protocols define standardized interaction patterns for agent workflows.\n * Returns just the protocol names; use {@link readProtocol} for content.\n *\n * @returns An array of protocol name strings\n *\n * @example\n * ```typescript\n * const protocols = listProtocols();\n * // e.g., [\"research\", \"implementation\", \"contribution\"]\n * ```\n *\n * @public\n */\nexport function listProtocols(): string[] {\n return getLibrary().listProtocols();\n}\n\n/**\n * Gets the absolute path to a protocol file.\n *\n * @remarks\n * Resolves the filesystem path for a protocol by name.\n * Returns undefined if the protocol does not exist.\n *\n * @param name - The protocol name to resolve\n * @returns The absolute path to the protocol file, or undefined if not found\n *\n * @example\n * ```typescript\n * const path = getProtocolPath(\"research\");\n * ```\n *\n * @public\n */\nexport function getProtocolPath(name: string): string | undefined {\n return getLibrary().getProtocolPath(name);\n}\n\n/**\n * Reads a protocol file's content as a string.\n *\n * @remarks\n * Reads the full content of a protocol file from disk.\n * Returns undefined if the protocol does not exist.\n *\n * @param name - The protocol name to read\n * @returns The text content of the protocol, or undefined if not found\n *\n * @example\n * ```typescript\n * const content = readProtocol(\"research\");\n * if (content) {\n * console.log(content);\n * }\n * ```\n *\n * @public\n */\nexport function readProtocol(name: string): string | undefined {\n return getLibrary().readProtocol(name);\n}\n\n/**\n * Validates a single skill's frontmatter against the schema.\n *\n * @remarks\n * Checks that the skill's SKILL.md file has valid YAML frontmatter\n * with all required fields. Returns a validation result with any errors.\n *\n * @param name - The skill name to validate\n * @returns A validation result indicating success or listing errors\n *\n * @example\n * ```typescript\n * const result = validateSkillFrontmatter(\"ct-orchestrator\");\n * if (!result.valid) {\n * console.error(result.errors);\n * }\n * ```\n *\n * @public\n */\nexport function validateSkillFrontmatter(name: string): SkillLibraryValidationResult {\n return getLibrary().validateSkillFrontmatter(name);\n}\n\n/**\n * Validates all skills in the catalog and returns results per skill.\n *\n * @remarks\n * Runs frontmatter validation on every skill in the library.\n * Returns a map keyed by skill name with validation results for each.\n *\n * @returns A map of skill names to their validation results\n *\n * @example\n * ```typescript\n * const results = validateAll();\n * for (const [name, result] of results) {\n * if (!result.valid) console.error(`${name}: invalid`);\n * }\n * ```\n *\n * @public\n */\nexport function validateAll(): Map<string, SkillLibraryValidationResult> {\n return getLibrary().validateAll();\n}\n\n/**\n * Gets the dispatch matrix from the skill library manifest.\n *\n * @remarks\n * The dispatch matrix maps protocol types to their corresponding skills,\n * enabling the orchestrator to route tasks to the correct executor.\n *\n * @returns The dispatch matrix object from the manifest\n *\n * @example\n * ```typescript\n * const matrix = getDispatchMatrix();\n * console.log(matrix);\n * ```\n *\n * @public\n */\nexport function getDispatchMatrix(): SkillLibraryDispatchMatrix {\n return getLibrary().getDispatchMatrix();\n}\n\n/**\n * Returns the skill library version string.\n *\n * @remarks\n * The version follows semver and corresponds to the version declared\n * in the library's manifest file.\n *\n * @returns The library version string\n *\n * @example\n * ```typescript\n * const version = getVersion();\n * // e.g., \"1.0.0\"\n * ```\n *\n * @public\n */\nexport function getVersion(): string {\n return getLibrary().version;\n}\n\n/**\n * Returns the absolute path to the skill library root directory.\n *\n * @remarks\n * This is the base directory from which all skill paths are resolved.\n * Set during library registration.\n *\n * @returns The absolute path to the library root\n *\n * @example\n * ```typescript\n * const root = getLibraryRoot();\n * // e.g., \"/home/user/.agents/skill-library\"\n * ```\n *\n * @public\n */\nexport function getLibraryRoot(): string {\n return getLibrary().libraryRoot;\n}\n","/**\n * Local skill discovery\n *\n * Scans directories for SKILL.md files and parses their frontmatter.\n */\n\nimport { readFile, readdir } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport { join, } from \"node:path\";\nimport matter from \"gray-matter\";\nimport type { SkillEntry, SkillMetadata } from \"../../types.js\";\n\n/**\n * Parse a SKILL.md file and extract its frontmatter metadata.\n *\n * @remarks\n * Reads the file, parses YAML frontmatter via `gray-matter`, and maps the\n * fields to a {@link SkillMetadata} object. Returns `null` if the file cannot\n * be read or lacks required `name` and `description` fields.\n *\n * @param filePath - Absolute path to the SKILL.md file\n * @returns Parsed metadata, or `null` if invalid\n *\n * @example\n * ```typescript\n * const meta = await parseSkillFile(\"/path/to/SKILL.md\");\n * if (meta) {\n * console.log(`${meta.name}: ${meta.description}`);\n * }\n * ```\n *\n * @public\n */\nexport async function parseSkillFile(filePath: string): Promise<SkillMetadata | null> {\n try {\n const content = await readFile(filePath, \"utf-8\");\n const { data } = matter(content);\n\n if (!data.name || !data.description) {\n return null;\n }\n\n const allowedTools = data[\"allowed-tools\"] ?? data.allowedTools;\n\n return {\n name: String(data.name),\n description: String(data.description),\n license: data.license ? String(data.license) : undefined,\n compatibility: data.compatibility ? String(data.compatibility) : undefined,\n metadata: data.metadata as Record<string, string> | undefined,\n allowedTools: typeof allowedTools === \"string\"\n ? allowedTools.split(/\\s+/)\n : Array.isArray(allowedTools)\n ? allowedTools.map(String)\n : undefined,\n version: data.version ? String(data.version) : undefined,\n };\n } catch {\n return null;\n }\n}\n\n/**\n * Discover a single skill at a given directory path.\n *\n * @remarks\n * Checks for a `SKILL.md` file in the directory and parses its metadata.\n *\n * @param skillDir - Absolute path to a skill directory (containing SKILL.md)\n * @returns Skill entry with metadata, or `null` if no valid SKILL.md exists\n *\n * @example\n * ```typescript\n * import { getCanonicalSkillsDir } from \"../paths/standard.js\";\n * import { join } from \"node:path\";\n *\n * const skill = await discoverSkill(join(getCanonicalSkillsDir(), \"my-skill\"));\n * if (skill) {\n * console.log(`Found: ${skill.name}`);\n * }\n * ```\n *\n * @public\n */\nexport async function discoverSkill(skillDir: string): Promise<SkillEntry | null> {\n const skillFile = join(skillDir, \"SKILL.md\");\n if (!existsSync(skillFile)) return null;\n\n const metadata = await parseSkillFile(skillFile);\n if (!metadata) return null;\n\n return {\n name: metadata.name,\n scopedName: metadata.name,\n path: skillDir,\n metadata,\n };\n}\n\n/**\n * Scan a directory for skill subdirectories, each containing a SKILL.md file.\n *\n * @remarks\n * Iterates over directories and symlinks in `rootDir` and calls\n * {@link discoverSkill} on each.\n *\n * @param rootDir - Absolute path to a skills root directory to scan\n * @returns Array of discovered skill entries\n *\n * @example\n * ```typescript\n * import { getCanonicalSkillsDir } from \"../paths/standard.js\";\n *\n * const skills = await discoverSkills(getCanonicalSkillsDir());\n * console.log(`Found ${skills.length} skills`);\n * ```\n *\n * @public\n */\nexport async function discoverSkills(rootDir: string): Promise<SkillEntry[]> {\n if (!existsSync(rootDir)) return [];\n\n const entries = await readdir(rootDir, { withFileTypes: true });\n const skills: SkillEntry[] = [];\n\n for (const entry of entries) {\n if (!entry.isDirectory() && !entry.isSymbolicLink()) continue;\n\n const skillDir = join(rootDir, entry.name);\n const skill = await discoverSkill(skillDir);\n if (skill) {\n skills.push(skill);\n }\n }\n\n return skills;\n}\n\n/**\n * Discover skills across multiple directories.\n *\n * @remarks\n * Scans each directory with {@link discoverSkills} and deduplicates results by\n * skill name, keeping the first occurrence found.\n *\n * @param dirs - Array of absolute paths to skills directories to scan\n * @returns Deduplicated array of discovered skill entries\n *\n * @example\n * ```typescript\n * const skills = await discoverSkillsMulti([\"/home/user/.agents/skills\", \"./project-skills\"]);\n * console.log(`Found ${skills.length} unique skills`);\n * ```\n *\n * @public\n */\nexport async function discoverSkillsMulti(dirs: string[]): Promise<SkillEntry[]> {\n const all: SkillEntry[] = [];\n const seen = new Set<string>();\n\n for (const dir of dirs) {\n const skills = await discoverSkills(dir);\n for (const skill of skills) {\n if (!seen.has(skill.name)) {\n seen.add(skill.name);\n all.push(skill);\n }\n }\n }\n\n return all;\n}\n","/**\n * Skills lock file management\n *\n * Shares the same canonical lock file as MCP.\n */\n\nimport type { LockEntry, SourceType } from \"../../types.js\";\nimport { readLockFile, updateLockFile } from \"../lock-utils.js\";\nimport { parseSource } from \"../sources/parser.js\";\nimport { simpleGit } from \"simple-git\";\nimport { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\n\nconst execFileAsync = promisify(execFile);\n\n/**\n * Record a skill installation in the lock file.\n *\n * @remarks\n * Creates or updates an entry in `lock.skills`. If the skill already exists,\n * the agent list is merged and `updatedAt` is refreshed while `installedAt` is preserved.\n *\n * @param skillName - Skill name\n * @param scopedName - Scoped name (may include marketplace scope)\n * @param source - Original source string\n * @param sourceType - Classified source type\n * @param agents - Provider IDs the skill was linked to\n * @param canonicalPath - Absolute path to the canonical installation\n * @param isGlobal - Whether this is a global installation\n * @param projectDir - Project directory (for project-scoped installs)\n * @param version - Version string or commit SHA\n *\n * @example\n * ```typescript\n * import { getCanonicalSkillsDir } from \"../paths/standard.js\";\n * import { join } from \"node:path\";\n *\n * await recordSkillInstall(\n * \"my-skill\", \"my-skill\", \"owner/repo\", \"github\",\n * [\"claude-code\"], join(getCanonicalSkillsDir(), \"my-skill\"), true,\n * );\n * ```\n *\n * @public\n */\nexport async function recordSkillInstall(\n skillName: string,\n scopedName: string,\n source: string,\n sourceType: SourceType,\n agents: string[],\n canonicalPath: string,\n isGlobal: boolean,\n projectDir?: string,\n version?: string,\n): Promise<void> {\n await updateLockFile((lock) => {\n const now = new Date().toISOString();\n const existing = lock.skills[skillName];\n\n lock.skills[skillName] = {\n name: skillName,\n scopedName: existing?.scopedName ?? scopedName,\n source: existing?.source ?? source,\n sourceType: existing?.sourceType ?? sourceType,\n version: version ?? existing?.version,\n installedAt: existing?.installedAt ?? now,\n updatedAt: now,\n agents: [...new Set([...(existing?.agents ?? []), ...agents])],\n canonicalPath,\n isGlobal: existing?.isGlobal ?? isGlobal,\n projectDir: existing?.projectDir ?? projectDir,\n };\n });\n}\n\n/**\n * Remove a skill entry from the lock file.\n *\n * @remarks\n * Deletes the skill's entry from `lock.skills` if it exists. Does not remove\n * any files from disk.\n *\n * @param skillName - Name of the skill to remove\n * @returns `true` if the entry was found and removed, `false` if not found\n *\n * @example\n * ```typescript\n * const removed = await removeSkillFromLock(\"my-skill\");\n * console.log(removed ? \"Removed\" : \"Not found\");\n * ```\n *\n * @public\n */\nexport async function removeSkillFromLock(skillName: string): Promise<boolean> {\n let removed = false;\n await updateLockFile((lock) => {\n if (!(skillName in lock.skills)) return;\n delete lock.skills[skillName];\n removed = true;\n });\n return removed;\n}\n\n/**\n * Get all skills tracked in the lock file.\n *\n * @remarks\n * Reads the lock file and returns the skills section as a record.\n *\n * @returns Record of skill name to lock entry\n *\n * @example\n * ```typescript\n * const skills = await getTrackedSkills();\n * for (const [name, entry] of Object.entries(skills)) {\n * console.log(`${name}: ${entry.source}`);\n * }\n * ```\n *\n * @public\n */\nexport async function getTrackedSkills(): Promise<Record<string, LockEntry>> {\n const lock = await readLockFile();\n return lock.skills;\n}\n\n/** Fetch the latest commit SHA for a GitHub/GitLab repo via ls-remote */\nasync function fetchLatestSha(\n repoUrl: string,\n ref?: string,\n): Promise<string | null> {\n try {\n const git = simpleGit();\n const target = ref ?? \"HEAD\";\n // Use --refs only for named refs (branches/tags), not for HEAD\n const args = target === \"HEAD\"\n ? [repoUrl, \"HEAD\"]\n : [\"--refs\", repoUrl, target];\n const result = await git.listRemote(args);\n const firstLine = result.trim().split(\"\\n\")[0];\n if (!firstLine) return null;\n const sha = firstLine.split(\"\\t\")[0];\n return sha ?? null;\n } catch {\n return null;\n }\n}\n\n/** Fetch the latest version for an npm package via npm view */\nasync function fetchLatestPackageVersion(packageName: string): Promise<string | null> {\n try {\n const { stdout } = await execFileAsync(\"npm\", [\"view\", packageName, \"version\"]);\n return stdout.trim() || null;\n } catch {\n return null;\n }\n}\n\n/**\n * Check if a skill has updates available by comparing the installed version\n * against the latest remote commit SHA.\n *\n * @remarks\n * Only supports GitHub, GitLab, and library (package-based) sources. Returns `\"unknown\"` for local,\n * package, or other source types.\n *\n * @param skillName - Name of the installed skill to check\n * @returns Object with update status, current version, and latest version\n *\n * @example\n * ```typescript\n * const update = await checkSkillUpdate(\"my-skill\");\n * if (update.hasUpdate) {\n * console.log(`Update available: ${update.currentVersion} -> ${update.latestVersion}`);\n * }\n * ```\n *\n * @public\n */\nexport async function checkSkillUpdate(skillName: string): Promise<{\n hasUpdate: boolean;\n currentVersion?: string;\n latestVersion?: string;\n status: \"up-to-date\" | \"update-available\" | \"unknown\";\n}> {\n const lock = await readLockFile();\n const entry = lock.skills[skillName];\n if (!entry) {\n return { hasUpdate: false, status: \"unknown\" };\n }\n\n // Only GitHub, GitLab, and library sources support remote checking\n if (entry.sourceType !== \"github\" && entry.sourceType !== \"gitlab\" && entry.sourceType !== \"library\") {\n return {\n hasUpdate: false,\n currentVersion: entry.version,\n status: \"unknown\",\n };\n }\n\n const parsed = parseSource(entry.source);\n if (!parsed.owner) {\n return {\n hasUpdate: false,\n currentVersion: entry.version,\n status: \"unknown\",\n };\n }\n\n if (entry.sourceType === \"library\") {\n const packageName = parsed.owner; // owner holds the package name for library type\n const latestVersion = await fetchLatestPackageVersion(packageName);\n if (!latestVersion) {\n return {\n hasUpdate: false,\n currentVersion: entry.version,\n status: \"unknown\",\n };\n }\n const currentVersion = entry.version;\n const hasUpdate = !currentVersion || currentVersion !== latestVersion;\n return {\n hasUpdate,\n currentVersion: currentVersion ?? \"unknown\",\n latestVersion,\n status: hasUpdate ? \"update-available\" : \"up-to-date\",\n };\n }\n\n if (!parsed.repo) {\n return {\n hasUpdate: false,\n currentVersion: entry.version,\n status: \"unknown\",\n };\n }\n\n const host = parsed.type === \"gitlab\" ? \"gitlab.com\" : \"github.com\";\n const repoUrl = `https://${host}/${parsed.owner}/${parsed.repo}.git`;\n const latestSha = await fetchLatestSha(repoUrl, parsed.ref);\n\n if (!latestSha) {\n return {\n hasUpdate: false,\n currentVersion: entry.version,\n status: \"unknown\",\n };\n }\n\n const currentVersion = entry.version;\n const hasUpdate = !currentVersion || !latestSha.startsWith(currentVersion.slice(0, 7));\n\n return {\n hasUpdate,\n currentVersion: currentVersion ?? \"unknown\",\n latestVersion: latestSha.slice(0, 12),\n status: hasUpdate ? \"update-available\" : \"up-to-date\",\n };\n}\n\n/**\n * Check for updates across all tracked skills.\n *\n * @remarks\n * Iterates over all skills in the lock file and checks each one concurrently\n * via {@link checkSkillUpdate}.\n *\n * @returns Object mapping skill names to their update status\n *\n * @example\n * ```typescript\n * const updates = await checkAllSkillUpdates();\n * for (const [name, status] of Object.entries(updates)) {\n * if (status.hasUpdate) {\n * console.log(`${name}: ${status.currentVersion} -> ${status.latestVersion}`);\n * }\n * }\n * ```\n *\n * @public\n */\nexport async function checkAllSkillUpdates(): Promise<Record<string, {\n hasUpdate: boolean;\n currentVersion?: string;\n latestVersion?: string;\n status: \"up-to-date\" | \"update-available\" | \"unknown\";\n}>> {\n const lock = await readLockFile();\n const skillNames = Object.keys(lock.skills);\n \n const results: Record<string, any> = {};\n await Promise.all(skillNames.map(async (name) => {\n results[name] = await checkSkillUpdate(name);\n }));\n \n return results;\n}\n","import type { MarketplaceResult } from \"../marketplace/types.js\";\n\n/**\n * Error codes used in skill recommendation validation.\n *\n * @remarks\n * These codes identify specific failure reasons when validating recommendation\n * criteria input. Each code maps to a human-readable error code string.\n *\n * @public\n */\nexport const RECOMMENDATION_ERROR_CODES = {\n QUERY_INVALID: \"E_SKILLS_QUERY_INVALID\",\n NO_MATCHES: \"E_SKILLS_NO_MATCHES\",\n SOURCE_UNAVAILABLE: \"E_SKILLS_SOURCE_UNAVAILABLE\",\n CRITERIA_CONFLICT: \"E_SKILLS_CRITERIA_CONFLICT\",\n} as const;\n\n/**\n * Union type of all recommendation error code string literals.\n *\n * @remarks\n * Derived from the values of {@link RECOMMENDATION_ERROR_CODES}. Used to type\n * the `code` field on validation issues.\n *\n * @public\n */\nexport type RecommendationErrorCode = (typeof RECOMMENDATION_ERROR_CODES)[keyof typeof RECOMMENDATION_ERROR_CODES];\n\n/**\n * Describes a single validation issue found in recommendation criteria.\n *\n * @remarks\n * Returned as part of {@link RecommendationValidationResult} when the input\n * criteria contain invalid or conflicting values.\n *\n * @public\n */\nexport interface RecommendationValidationIssue {\n /** The error code identifying the type of validation failure. */\n code: RecommendationErrorCode;\n /** The criteria field that caused the validation issue. */\n field: \"query\" | \"mustHave\" | \"prefer\" | \"exclude\";\n /** A human-readable description of the validation issue. */\n message: string;\n}\n\n/**\n * Result of validating recommendation criteria input.\n *\n * @remarks\n * When `valid` is true, the `issues` array is empty and the criteria can be\n * safely normalized for scoring. When `valid` is false, each issue describes\n * a specific problem that must be corrected.\n *\n * @public\n */\nexport interface RecommendationValidationResult {\n /** Whether the criteria passed all validation checks. */\n valid: boolean;\n /** List of validation issues found, empty when valid. */\n issues: RecommendationValidationIssue[];\n}\n\n/**\n * Raw user-provided criteria for skill recommendations.\n *\n * @remarks\n * All fields are optional, but at least one must be provided. String values\n * containing commas are tokenized into multiple terms. Arrays are flattened\n * and deduplicated during normalization.\n *\n * @public\n */\nexport interface RecommendationCriteriaInput {\n /** Free-text search query to match against skill metadata. */\n query?: string;\n /** Terms that a skill must match to be considered relevant. */\n mustHave?: string | string[];\n /** Terms that boost a skill's score when matched. */\n prefer?: string | string[];\n /** Terms that penalize a skill's score when matched. */\n exclude?: string | string[];\n}\n\n/**\n * Normalized and tokenized form of recommendation criteria.\n *\n * @remarks\n * Produced by {@link normalizeRecommendationCriteria} from raw\n * {@link RecommendationCriteriaInput}. All values are lowercased, deduplicated,\n * and sorted for deterministic scoring.\n *\n * @public\n */\nexport interface NormalizedRecommendationCriteria {\n /** The lowercased, trimmed query string. */\n query: string;\n /** Individual tokens extracted from the query string. */\n queryTokens: string[];\n /** Sorted, deduplicated list of required match terms. */\n mustHave: string[];\n /** Sorted, deduplicated list of preferred match terms. */\n prefer: string[];\n /** Sorted, deduplicated list of exclusion terms. */\n exclude: string[];\n}\n\n/**\n * String literal union of all reason codes emitted during skill scoring.\n *\n * @remarks\n * Each code corresponds to a specific scoring signal, such as matching a\n * required term, detecting a modern marker, or applying an exclusion penalty.\n * Used in {@link RecommendationReason} to explain score contributions.\n *\n * @public\n */\nexport type RecommendationReasonCode =\n | \"MATCH_TOPIC_GITBOOK\"\n | \"HAS_GIT_SYNC\"\n | \"HAS_API_WORKFLOW\"\n | \"PENALTY_LEGACY_CLI\"\n | \"MUST_HAVE_MATCH\"\n | \"MISSING_MUST_HAVE\"\n | \"PREFER_MATCH\"\n | \"QUERY_MATCH\"\n | \"STAR_SIGNAL\"\n | \"METADATA_SIGNAL\"\n | \"MODERN_MARKER\"\n | \"LEGACY_MARKER\"\n | \"EXCLUDE_MATCH\";\n\n/**\n * A single reason contributing to a skill's recommendation score.\n *\n * @remarks\n * Each reason captures one scoring signal with an optional detail string\n * providing additional context such as match counts.\n *\n * @public\n */\nexport interface RecommendationReason {\n /** The reason code identifying the scoring signal. */\n code: RecommendationReasonCode;\n /** Optional detail providing additional context, such as match count. */\n detail?: string;\n}\n\n/**\n * Detailed breakdown of a skill's recommendation score by category.\n *\n * @remarks\n * Only populated when `includeDetails` is true in {@link RecommendationOptions}.\n * Each field represents the weighted contribution of a scoring category to the\n * total score.\n *\n * @public\n */\nexport interface RecommendationScoreBreakdown {\n /** Score contribution from must-have term matches. */\n mustHave: number;\n /** Score contribution from preferred term matches. */\n prefer: number;\n /** Score contribution from query token matches. */\n query: number;\n /** Score contribution from repository star count signal. */\n stars: number;\n /** Score contribution from metadata quality and source confidence. */\n metadata: number;\n /** Score contribution from modern vs legacy marker detection. */\n modernity: number;\n /** Penalty applied for matching excluded terms. */\n exclusionPenalty: number;\n /** The final aggregated recommendation score. */\n total: number;\n}\n\n/**\n * A single skill recommendation with its computed score and explanations.\n *\n * @remarks\n * Produced by {@link scoreSkillRecommendation} for each candidate skill.\n * Contains the raw score, human-readable reasons, tradeoff warnings, and\n * an optional detailed breakdown.\n *\n * @public\n */\nexport interface RankedSkillRecommendation {\n /** The marketplace skill result being scored. */\n skill: MarketplaceResult;\n /** The computed recommendation score, higher is better. */\n score: number;\n /** List of reasons explaining the score contributions. */\n reasons: RecommendationReason[];\n /** Human-readable tradeoff warnings for the skill. */\n tradeoffs: string[];\n /** Whether the skill matched one or more exclusion terms. */\n excluded: boolean;\n /** Optional detailed score breakdown by category. */\n breakdown?: RecommendationScoreBreakdown;\n}\n\n/**\n * Configuration options for the skill recommendation engine.\n *\n * @remarks\n * All fields are optional and have sensible defaults. Custom weights override\n * individual scoring factors while preserving defaults for unspecified weights.\n *\n * @public\n */\nexport interface RecommendationOptions {\n /** Maximum number of results to return from the ranked list. */\n top?: number;\n /** Whether to include detailed score breakdown in each result. */\n includeDetails?: boolean;\n /** Partial weight overrides for individual scoring factors. */\n weights?: Partial<RecommendationWeights>;\n /** Custom modern technology marker strings for modernity scoring. */\n modernMarkers?: string[];\n /** Custom legacy technology marker strings for modernity scoring. */\n legacyMarkers?: string[];\n}\n\n/**\n * Numeric weights controlling the recommendation scoring algorithm.\n *\n * @remarks\n * Each weight multiplies the corresponding match count or signal value.\n * Higher values increase the influence of that factor on the total score.\n * Penalty weights are subtracted from the total.\n *\n * @public\n */\nexport interface RecommendationWeights {\n /** Weight applied per must-have term match. */\n mustHaveMatch: number;\n /** Weight applied per preferred term match. */\n preferMatch: number;\n /** Weight applied per query token match. */\n queryTokenMatch: number;\n /** Multiplier for the logarithmic star count signal. */\n starsFactor: number;\n /** Boost for metadata quality and source confidence. */\n metadataBoost: number;\n /** Boost applied per modern technology marker match. */\n modernMarkerBoost: number;\n /** Penalty applied per legacy technology marker match. */\n legacyMarkerPenalty: number;\n /** Penalty applied per excluded term match. */\n excludePenalty: number;\n /** Penalty applied per missing must-have term. */\n missingMustHavePenalty: number;\n}\n\n/**\n * The complete result of a skill recommendation operation.\n *\n * @remarks\n * Contains the normalized criteria that were used for scoring and the\n * ranked list of skill recommendations sorted by descending score.\n *\n * @public\n */\nexport interface RecommendSkillsResult {\n /** The normalized criteria used for scoring. */\n criteria: NormalizedRecommendationCriteria;\n /** Skills ranked by recommendation score, highest first. */\n ranking: RankedSkillRecommendation[];\n}\n\nconst DEFAULT_WEIGHTS: RecommendationWeights = {\n mustHaveMatch: 10,\n preferMatch: 4,\n queryTokenMatch: 3,\n starsFactor: 2,\n metadataBoost: 2,\n modernMarkerBoost: 3,\n legacyMarkerPenalty: 3,\n excludePenalty: 25,\n missingMustHavePenalty: 20,\n};\n\nconst DEFAULT_MODERN_MARKERS = [\"svelte 5\", \"runes\", \"lafs\", \"slsa\", \"drizzle\", \"better-auth\"];\nconst DEFAULT_LEGACY_MARKERS = [\"svelte 3\", \"jquery\", \"bower\", \"legacy\", \"book.json\", \"gitbook-cli\"];\n\n/**\n * Splits a comma-separated criteria string into normalized tokens.\n *\n * @remarks\n * Each token is trimmed and lowercased. Empty tokens are removed.\n * This is the core tokenization used by the recommendation engine to\n * process user-provided criteria values.\n *\n * @param value - The comma-separated string to tokenize\n * @returns An array of trimmed, lowercased, non-empty tokens\n *\n * @example\n * ```typescript\n * const tokens = tokenizeCriteriaValue(\"React, TypeScript, svelte\");\n * // returns [\"react\", \"typescript\", \"svelte\"]\n * ```\n *\n * @public\n */\nexport function tokenizeCriteriaValue(value: string): string[] {\n return value\n .split(\",\")\n .map((part) => part.trim().toLowerCase())\n .filter(Boolean);\n}\n\nfunction normalizeList(value: unknown): string[] {\n if (value === undefined) return [];\n\n if (!(typeof value === \"string\" || Array.isArray(value))) return [];\n\n const source = Array.isArray(value) ? value : [value];\n const flattened = source.flatMap((item) => (typeof item === \"string\" ? tokenizeCriteriaValue(item) : []));\n return Array.from(new Set(flattened)).sort((a, b) => a.localeCompare(b));\n}\n\nfunction hasAnyCriteriaInput(input: RecommendationCriteriaInput): boolean {\n const query = typeof input.query === \"string\" ? input.query.trim() : \"\";\n if (query.length > 0) return true;\n\n const lists = [input.mustHave, input.prefer, input.exclude];\n return lists.some((list) => normalizeList(list).length > 0);\n}\n\n/**\n * Validates recommendation criteria input for correctness and consistency.\n *\n * @remarks\n * Checks that all fields have valid types, that no terms appear in both\n * inclusion and exclusion lists, and that at least one criteria value is\n * provided. Returns a result with `valid: true` when all checks pass.\n *\n * @param input - The raw recommendation criteria to validate\n * @returns A validation result indicating success or listing all issues\n *\n * @example\n * ```typescript\n * const result = validateRecommendationCriteria({\n * query: \"gitbook\",\n * mustHave: \"api\",\n * exclude: \"legacy\",\n * });\n * if (!result.valid) {\n * console.error(result.issues);\n * }\n * ```\n *\n * @public\n */\nexport function validateRecommendationCriteria(input: RecommendationCriteriaInput): RecommendationValidationResult {\n const issues: RecommendationValidationIssue[] = [];\n\n if (input.query !== undefined && typeof input.query !== \"string\") {\n issues.push({\n code: RECOMMENDATION_ERROR_CODES.QUERY_INVALID,\n field: \"query\",\n message: \"query must be a string\",\n });\n }\n\n if (input.mustHave !== undefined && !(typeof input.mustHave === \"string\" || Array.isArray(input.mustHave))) {\n issues.push({\n code: RECOMMENDATION_ERROR_CODES.QUERY_INVALID,\n field: \"mustHave\",\n message: \"mustHave must be a string or string[]\",\n });\n }\n\n if (input.prefer !== undefined && !(typeof input.prefer === \"string\" || Array.isArray(input.prefer))) {\n issues.push({\n code: RECOMMENDATION_ERROR_CODES.QUERY_INVALID,\n field: \"prefer\",\n message: \"prefer must be a string or string[]\",\n });\n }\n\n if (input.exclude !== undefined && !(typeof input.exclude === \"string\" || Array.isArray(input.exclude))) {\n issues.push({\n code: RECOMMENDATION_ERROR_CODES.QUERY_INVALID,\n field: \"exclude\",\n message: \"exclude must be a string or string[]\",\n });\n }\n\n const mustHave = normalizeList(input.mustHave);\n const prefer = normalizeList(input.prefer);\n const exclude = normalizeList(input.exclude);\n const conflict = mustHave.some((term) => exclude.includes(term)) || prefer.some((term) => exclude.includes(term));\n if (conflict) {\n issues.push({\n code: RECOMMENDATION_ERROR_CODES.CRITERIA_CONFLICT,\n field: \"exclude\",\n message: \"criteria terms cannot appear in both prefer/must-have and exclude\",\n });\n }\n\n if (issues.length === 0 && !hasAnyCriteriaInput(input)) {\n issues.push({\n code: RECOMMENDATION_ERROR_CODES.QUERY_INVALID,\n field: \"query\",\n message: \"at least one criteria value is required\",\n });\n }\n\n return {\n valid: issues.length === 0,\n issues,\n };\n}\n\n/**\n * Normalizes raw recommendation criteria into a consistent tokenized form.\n *\n * @remarks\n * Lowercases all values, tokenizes comma-separated strings, deduplicates\n * terms, and sorts lists alphabetically. The result is deterministic for\n * equivalent inputs, ensuring consistent scoring behavior.\n *\n * @param input - The raw recommendation criteria to normalize\n * @returns Normalized criteria with tokenized, sorted, deduplicated terms\n *\n * @example\n * ```typescript\n * const criteria = normalizeRecommendationCriteria({\n * query: \"GitBook API\",\n * mustHave: \"sync, api\",\n * prefer: [\"modern\"],\n * });\n * // criteria.queryTokens => [\"api\", \"gitbook\"]\n * // criteria.mustHave => [\"api\", \"sync\"]\n * ```\n *\n * @public\n */\nexport function normalizeRecommendationCriteria(input: RecommendationCriteriaInput): NormalizedRecommendationCriteria {\n const query = (input.query ?? \"\").trim().toLowerCase();\n return {\n query,\n queryTokens: query ? Array.from(new Set(tokenizeCriteriaValue(query.replace(/\\s+/g, \",\")))).sort((a, b) => a.localeCompare(b)) : [],\n mustHave: normalizeList(input.mustHave),\n prefer: normalizeList(input.prefer),\n exclude: normalizeList(input.exclude),\n };\n}\n\nfunction countMatches(haystack: string, needles: string[]): number {\n let count = 0;\n for (const needle of needles) {\n if (haystack.includes(needle)) {\n count += 1;\n }\n }\n return count;\n}\n\nfunction clampScore(value: number): number {\n return Number(value.toFixed(6));\n}\n\nfunction buildSearchText(skill: MarketplaceResult): string {\n return `${skill.name} ${skill.scopedName} ${skill.description} ${skill.author}`.toLowerCase();\n}\n\n/**\n * Computes a recommendation score for a single skill against normalized criteria.\n *\n * @remarks\n * Evaluates the skill across multiple scoring dimensions including must-have\n * matches, preferred term matches, query token matches, star count signals,\n * metadata quality, modern/legacy markers, and exclusion penalties. The total\n * score is the weighted sum of all dimensions. When `includeDetails` is true,\n * a full breakdown by category is attached to the result.\n *\n * @param skill - The marketplace skill result to score\n * @param criteria - The normalized recommendation criteria to score against\n * @param options - Optional scoring configuration including weights and markers\n * @returns A ranked recommendation with score, reasons, and tradeoffs\n *\n * @example\n * ```typescript\n * const criteria = normalizeRecommendationCriteria({ query: \"gitbook\" });\n * const ranked = scoreSkillRecommendation(marketplaceSkill, criteria, {\n * includeDetails: true,\n * });\n * console.log(ranked.score, ranked.reasons);\n * ```\n *\n * @public\n */\nexport function scoreSkillRecommendation(\n skill: MarketplaceResult,\n criteria: NormalizedRecommendationCriteria,\n options: RecommendationOptions = {},\n): RankedSkillRecommendation {\n const weights = { ...DEFAULT_WEIGHTS, ...options.weights };\n const modernMarkers = (options.modernMarkers ?? DEFAULT_MODERN_MARKERS).map((marker) => marker.toLowerCase());\n const legacyMarkers = (options.legacyMarkers ?? DEFAULT_LEGACY_MARKERS).map((marker) => marker.toLowerCase());\n const text = buildSearchText(skill);\n const reasons: RecommendationReason[] = [];\n const tradeoffs: string[] = [];\n\n const mustHaveMatches = countMatches(text, criteria.mustHave);\n const missingMustHave = Math.max(criteria.mustHave.length - mustHaveMatches, 0);\n const preferMatches = countMatches(text, criteria.prefer);\n const queryMatches = countMatches(text, criteria.queryTokens);\n const excludeMatches = countMatches(text, criteria.exclude);\n const modernMatches = countMatches(text, modernMarkers);\n const legacyMatches = countMatches(text, legacyMarkers);\n const metadataSignal = skill.description.trim().length >= 80 ? 1 : 0;\n const starsSignal = Math.log10(skill.stars + 1);\n const sourceConfidence = skill.source === \"agentskills.in\"\n ? 1\n : skill.source === \"skills.sh\"\n ? 0.8\n : 0.6;\n\n const mustHaveScore = (mustHaveMatches * weights.mustHaveMatch) - (missingMustHave * weights.missingMustHavePenalty);\n const preferScore = preferMatches * weights.preferMatch;\n const queryScore = queryMatches * weights.queryTokenMatch;\n const starsScore = starsSignal * weights.starsFactor;\n const metadataScore = (metadataSignal + sourceConfidence) * weights.metadataBoost;\n const modernityScore =\n (modernMatches * weights.modernMarkerBoost) - (legacyMatches * weights.legacyMarkerPenalty);\n const exclusionPenalty = excludeMatches * weights.excludePenalty;\n\n const hasGitbookTopic = text.includes(\"gitbook\");\n const hasGitSync = text.includes(\"git sync\") || (text.includes(\"git\") && text.includes(\"sync\"));\n const hasApiWorkflow = text.includes(\"api\") && (text.includes(\"workflow\") || text.includes(\"sync\"));\n const hasLegacyCli = text.includes(\"gitbook-cli\") || text.includes(\"book.json\");\n\n const topicScore = (hasGitbookTopic ? 3 : 0) + (hasGitSync ? 2 : 0) + (hasApiWorkflow ? 2 : 0) - (hasLegacyCli ? 4 : 0);\n\n const total = clampScore(\n mustHaveScore + preferScore + queryScore + starsScore + metadataScore + modernityScore + topicScore - exclusionPenalty,\n );\n\n if (hasGitbookTopic) reasons.push({ code: \"MATCH_TOPIC_GITBOOK\" });\n if (hasGitSync) reasons.push({ code: \"HAS_GIT_SYNC\" });\n if (hasApiWorkflow) reasons.push({ code: \"HAS_API_WORKFLOW\" });\n if (hasLegacyCli) reasons.push({ code: \"PENALTY_LEGACY_CLI\" });\n\n if (mustHaveMatches > 0) reasons.push({ code: \"MUST_HAVE_MATCH\", detail: String(mustHaveMatches) });\n if (missingMustHave > 0) reasons.push({ code: \"MISSING_MUST_HAVE\", detail: String(missingMustHave) });\n if (preferMatches > 0) reasons.push({ code: \"PREFER_MATCH\", detail: String(preferMatches) });\n if (queryMatches > 0) reasons.push({ code: \"QUERY_MATCH\", detail: String(queryMatches) });\n if (starsSignal > 0) reasons.push({ code: \"STAR_SIGNAL\" });\n if (metadataSignal > 0) reasons.push({ code: \"METADATA_SIGNAL\" });\n if (modernMatches > 0) reasons.push({ code: \"MODERN_MARKER\", detail: String(modernMatches) });\n if (legacyMatches > 0) reasons.push({ code: \"LEGACY_MARKER\", detail: String(legacyMatches) });\n if (excludeMatches > 0) reasons.push({ code: \"EXCLUDE_MATCH\", detail: String(excludeMatches) });\n\n if (missingMustHave > 0) tradeoffs.push(\"Missing one or more required criteria terms.\");\n if (excludeMatches > 0) tradeoffs.push(\"Matches one or more excluded terms.\");\n if (skill.stars < 10) tradeoffs.push(\"Low quality signal from repository stars.\");\n if (hasLegacyCli) tradeoffs.push(\"Contains legacy GitBook CLI markers.\");\n\n const result: RankedSkillRecommendation = {\n skill,\n score: total,\n reasons,\n tradeoffs,\n excluded: excludeMatches > 0,\n };\n\n if (options.includeDetails) {\n result.breakdown = {\n mustHave: clampScore(mustHaveScore),\n prefer: clampScore(preferScore),\n query: clampScore(queryScore),\n stars: clampScore(starsScore),\n metadata: clampScore(metadataScore),\n modernity: clampScore(modernityScore),\n exclusionPenalty: clampScore(exclusionPenalty),\n total,\n };\n }\n\n return result;\n}\n\n/**\n * Validates, normalizes, scores, and ranks a list of skills against criteria.\n *\n * @remarks\n * This is the primary entry point for the recommendation engine. It validates\n * the input criteria, throws on invalid input, then scores each skill and\n * returns them sorted by descending score. Ties are broken by star count, then\n * alphabetically by scoped name. Results can be limited via `options.top`.\n *\n * @param skills - The array of marketplace skill results to rank\n * @param criteriaInput - The raw recommendation criteria from the user\n * @param options - Optional configuration for scoring and result limiting\n * @returns The normalized criteria and ranked skill recommendations\n * @throws Error with `code` and `issues` properties when criteria are invalid\n *\n * @example\n * ```typescript\n * const result = recommendSkills(\n * marketplaceResults,\n * { query: \"gitbook\", mustHave: \"api\", exclude: \"legacy\" },\n * { top: 5, includeDetails: true },\n * );\n * for (const rec of result.ranking) {\n * console.log(rec.skill.name, rec.score);\n * }\n * ```\n *\n * @public\n */\nexport function recommendSkills(\n skills: MarketplaceResult[],\n criteriaInput: RecommendationCriteriaInput,\n options: RecommendationOptions = {},\n): RecommendSkillsResult {\n const validation = validateRecommendationCriteria(criteriaInput);\n if (!validation.valid) {\n const first = validation.issues[0];\n const error = new Error(first?.message ?? \"Invalid recommendation criteria\") as Error & {\n code?: RecommendationErrorCode;\n issues?: RecommendationValidationIssue[];\n };\n error.code = first?.code;\n error.issues = validation.issues;\n throw error;\n }\n\n const criteria = normalizeRecommendationCriteria(criteriaInput);\n const ranking = skills\n .map((skill) => scoreSkillRecommendation(skill, criteria, options))\n .sort((a, b) => {\n if (b.score !== a.score) return b.score - a.score;\n if (b.skill.stars !== a.skill.stars) return b.skill.stars - a.skill.stars;\n return a.skill.scopedName.localeCompare(b.skill.scopedName);\n });\n\n return {\n criteria,\n ranking: typeof options.top === \"number\" ? ranking.slice(0, Math.max(0, options.top)) : ranking,\n };\n}\n\n/**\n * Alias for {@link recommendSkills} providing a shorter function name.\n *\n * @remarks\n * This is a convenience alias that exposes the same recommendation engine\n * under the name `rankSkills` for backward compatibility.\n *\n * @public\n */\nexport const rankSkills = recommendSkills;\n","import { MarketplaceClient } from \"../marketplace/client.js\";\nimport {\n RECOMMENDATION_ERROR_CODES,\n recommendSkills as rankSkills,\n type RecommendationCriteriaInput,\n type RecommendationOptions,\n type RecommendSkillsResult,\n} from \"./recommendation.js\";\n\n/**\n * Options for searching skills via marketplace APIs.\n *\n * @public\n */\nexport interface SearchSkillsOptions {\n /** Maximum number of results to return. */\n limit?: number;\n}\n\n/**\n * Options for the recommendation query combining ranking options with a result limit.\n *\n * @public\n */\nexport interface RecommendSkillsQueryOptions extends RecommendationOptions {\n /** Maximum number of results to return. */\n limit?: number;\n}\n\n/**\n * Format skill recommendation results for display or serialization.\n *\n * @remarks\n * In `\"human\"` mode, produces a numbered list with reasons and tradeoffs.\n * In `\"json\"` mode, returns a structured object suitable for machine consumption.\n *\n * @param result - The recommendation result to format\n * @param opts - Formatting options including output mode and detail level\n * @returns Formatted string for human mode, or a structured object for JSON mode\n *\n * @example\n * ```typescript\n * const result = await recommendSkills(\"testing\", { taskType: \"test-writing\" });\n * const output = formatSkillRecommendations(result, { mode: \"human\" });\n * console.log(output);\n * ```\n *\n * @public\n */\nexport function formatSkillRecommendations(\n result: RecommendSkillsResult,\n opts: { mode: \"human\" | \"json\"; details?: boolean },\n): string | Record<string, unknown> {\n const top = result.ranking;\n\n if (opts.mode === \"human\") {\n if (top.length === 0) return \"No recommendations found.\";\n const lines: string[] = [\"Recommended skills:\", \"\"];\n for (const [index, entry] of top.entries()) {\n const marker = index === 0 ? \" (Recommended)\" : \"\";\n lines.push(`${index + 1}) ${entry.skill.scopedName}${marker}`);\n lines.push(` why: ${entry.reasons.map((reason) => reason.code).join(\", \") || \"score-based match\"}`);\n lines.push(` tradeoff: ${entry.tradeoffs[0] ?? \"none\"}`);\n }\n lines.push(\"\");\n lines.push(`CHOOSE: ${top.map((_, index) => index + 1).join(\",\")}`);\n return lines.join(\"\\n\");\n }\n\n const options = top.map((entry, index) => ({\n rank: index + 1,\n scopedName: entry.skill.scopedName,\n score: entry.score,\n reasons: entry.reasons,\n tradeoffs: entry.tradeoffs,\n ...(opts.details\n ? {\n description: entry.skill.description,\n source: entry.skill.source,\n evidence: entry.breakdown ?? null,\n }\n : {}),\n }));\n\n return {\n query: result.criteria.query,\n recommended: options[0] ?? null,\n options,\n };\n}\n\n/**\n * Search for skills via marketplace APIs.\n *\n * @remarks\n * Queries the unified marketplace client and returns matching skill entries.\n * Throws with a coded error if the query is empty or the marketplace is unavailable.\n *\n * @param query - Search query string (must be non-empty)\n * @param options - Search options including result limit\n * @returns Array of marketplace skill entries matching the query\n *\n * @example\n * ```typescript\n * const results = await searchSkills(\"test runner\", { limit: 10 });\n * console.log(`Found ${results.length} skills`);\n * ```\n *\n * @public\n */\nexport async function searchSkills(query: string, options: SearchSkillsOptions = {}) {\n const trimmed = query.trim();\n if (!trimmed) {\n const error = new Error(\"query must be non-empty\") as Error & { code?: string };\n error.code = RECOMMENDATION_ERROR_CODES.QUERY_INVALID;\n throw error;\n }\n\n const client = new MarketplaceClient();\n try {\n return await client.search(trimmed, options.limit ?? 20);\n } catch (error) {\n const wrapped = new Error(error instanceof Error ? error.message : String(error)) as Error & { code?: string };\n wrapped.code = RECOMMENDATION_ERROR_CODES.SOURCE_UNAVAILABLE;\n throw wrapped;\n }\n}\n\n/**\n * Search and rank skills based on query and recommendation criteria.\n *\n * @remarks\n * Combines marketplace search with the recommendation engine to produce\n * scored, ranked skill suggestions. Throws if no matches are found.\n *\n * @param query - Search query string\n * @param criteria - Recommendation criteria (task type, context, preferences)\n * @param options - Options for limiting and tuning results\n * @returns Ranked recommendation results with scores and reasons\n *\n * @example\n * ```typescript\n * const result = await recommendSkills(\"testing\", { taskType: \"test-writing\" });\n * const best = result.ranking[0];\n * console.log(`Top pick: ${best.skill.scopedName} (score: ${best.score})`);\n * ```\n *\n * @public\n */\nexport async function recommendSkills(\n query: string,\n criteria: Omit<RecommendationCriteriaInput, \"query\">,\n options: RecommendSkillsQueryOptions = {},\n): Promise<RecommendSkillsResult> {\n const hits = await searchSkills(query, { limit: options.limit ?? Math.max((options.top ?? 3) * 5, 20) });\n const ranked = rankSkills(hits, { ...criteria, query }, options);\n\n if (ranked.ranking.length === 0) {\n const error = new Error(\"no matches found\") as Error & { code?: string };\n error.code = RECOMMENDATION_ERROR_CODES.NO_MATCHES;\n throw error;\n }\n\n return ranked;\n}\n","/**\n * Security scanning engine for SKILL.md files\n *\n * Scans skill content against 46+ security rules\n * and produces findings with line-level precision.\n */\n\nimport { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport type { AuditFinding, AuditResult, AuditRule, AuditSeverity } from \"../../../types.js\";\nimport { AUDIT_RULES } from \"./rules.js\";\n\nconst SEVERITY_WEIGHTS: Record<AuditSeverity, number> = {\n critical: 25,\n high: 15,\n medium: 8,\n low: 3,\n info: 0,\n};\n\n/**\n * Scan a single file against security audit rules.\n *\n * @remarks\n * Checks each line of the file against all active rules and produces findings\n * with line-level precision. Calculates a security score (100 = clean, 0 = dangerous)\n * based on severity-weighted penalties.\n *\n * @param filePath - Absolute path to the file to scan\n * @param rules - Custom rules to scan against (defaults to the built-in 46+ rules)\n * @returns Audit result with findings, score, and pass/fail status\n *\n * @example\n * ```typescript\n * const result = await scanFile(\"/path/to/SKILL.md\");\n * console.log(`Score: ${result.score}/100, Passed: ${result.passed}`);\n * ```\n *\n * @public\n */\nexport async function scanFile(\n filePath: string,\n rules?: AuditRule[],\n): Promise<AuditResult> {\n if (!existsSync(filePath)) {\n return { file: filePath, findings: [], score: 100, passed: true };\n }\n\n const content = await readFile(filePath, \"utf-8\");\n const lines = content.split(\"\\n\");\n const activeRules = rules ?? AUDIT_RULES;\n const findings: AuditFinding[] = [];\n\n for (const rule of activeRules) {\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i] ?? \"\";\n const match = line.match(rule.pattern);\n if (match) {\n findings.push({\n rule,\n line: i + 1,\n column: (match.index ?? 0) + 1,\n match: match[0],\n context: line.trim(),\n });\n }\n }\n }\n\n // Calculate score (100 = clean, 0 = very dangerous)\n const totalPenalty = findings.reduce(\n (sum, f) => sum + (SEVERITY_WEIGHTS[f.rule.severity] ?? 0),\n 0,\n );\n const score = Math.max(0, 100 - totalPenalty);\n const passed = !findings.some((f) => f.rule.severity === \"critical\" || f.rule.severity === \"high\");\n\n return { file: filePath, findings, score, passed };\n}\n\n/**\n * Scan a directory of skills for security issues.\n *\n * @remarks\n * Iterates over skill subdirectories and scans each `SKILL.md` file found.\n *\n * @param dirPath - Absolute path to the skills directory to scan\n * @returns Array of audit results, one per scanned SKILL.md\n *\n * @example\n * ```typescript\n * import { getCanonicalSkillsDir } from \"../../paths/standard.js\";\n *\n * const results = await scanDirectory(getCanonicalSkillsDir());\n * const failing = results.filter(r => !r.passed);\n * ```\n *\n * @public\n */\nexport async function scanDirectory(dirPath: string): Promise<AuditResult[]> {\n const { readdir } = await import(\"node:fs/promises\");\n const { join } = await import(\"node:path\");\n\n if (!existsSync(dirPath)) return [];\n\n const entries = await readdir(dirPath, { withFileTypes: true });\n const results: AuditResult[] = [];\n\n for (const entry of entries) {\n if (entry.isDirectory() || entry.isSymbolicLink()) {\n const skillFile = join(dirPath, entry.name, \"SKILL.md\");\n if (existsSync(skillFile)) {\n results.push(await scanFile(skillFile));\n }\n }\n }\n\n return results;\n}\n\n/**\n * Convert audit results to SARIF 2.1.0 format (Static Analysis Results Interchange Format).\n *\n * @remarks\n * Produces a standards-compliant SARIF document suitable for CI/CD integration\n * and code scanning tools (e.g. GitHub Code Scanning).\n *\n * @param results - Array of audit results to convert\n * @returns SARIF 2.1.0 JSON object\n *\n * @example\n * ```typescript\n * const results = await scanDirectory(\"/path/to/skills\");\n * const sarif = toSarif(results);\n * writeFileSync(\"audit.sarif\", JSON.stringify(sarif, null, 2));\n * ```\n *\n * @public\n */\nexport function toSarif(results: AuditResult[]): object {\n return {\n $schema: \"https://raw.githubusercontent.com/oasis-tcs/sarif-spec/main/sarif-2.1/schema/sarif-schema-2.1.0.json\",\n version: \"2.1.0\",\n runs: [\n {\n tool: {\n driver: {\n name: \"caamp-audit\",\n version: \"0.1.0\",\n rules: AUDIT_RULES.map((r) => ({\n id: r.id,\n name: r.name,\n shortDescription: { text: r.description },\n defaultConfiguration: {\n level: r.severity === \"critical\" || r.severity === \"high\" ? \"error\" : \"warning\",\n },\n properties: { category: r.category },\n })),\n },\n },\n results: results.flatMap((result) =>\n result.findings.map((f) => ({\n ruleId: f.rule.id,\n level: f.rule.severity === \"critical\" || f.rule.severity === \"high\" ? \"error\" : \"warning\",\n message: { text: `${f.rule.description}: ${f.match}` },\n locations: [\n {\n physicalLocation: {\n artifactLocation: { uri: result.file },\n region: {\n startLine: f.line,\n startColumn: f.column,\n },\n },\n },\n ],\n })),\n ),\n },\n ],\n };\n}\n","/**\n * Security audit rules for SKILL.md scanning\n *\n * 46+ rules across categories: prompt injection, command injection,\n * data exfiltration, privilege escalation, obfuscation, and more.\n */\n\nimport type { AuditRule, AuditSeverity } from \"../../../types.js\";\n\nfunction rule(\n id: string,\n name: string,\n description: string,\n severity: AuditSeverity,\n category: string,\n pattern: RegExp,\n): AuditRule {\n return { id, name, description, severity, category, pattern };\n}\n\n/**\n * Complete set of security audit rules for SKILL.md scanning.\n *\n * @remarks\n * Contains 46+ rules covering prompt injection, command injection, data exfiltration,\n * privilege escalation, filesystem abuse, network abuse, obfuscation, supply chain,\n * and information disclosure categories.\n *\n * @public\n */\nexport const AUDIT_RULES: AuditRule[] = [\n // ── Prompt Injection ────────────────────────────────────────\n rule(\"PI001\", \"System prompt override\", \"Attempts to override system instructions\", \"critical\", \"prompt-injection\",\n /(?:ignore|forget|disregard)\\s+(?:all\\s+)?(?:previous|prior|above|system)\\s+(?:instructions|prompts|rules)/i),\n rule(\"PI002\", \"Role manipulation\", \"Attempts to assume a different role\", \"critical\", \"prompt-injection\",\n /(?:you\\s+are\\s+now|act\\s+as|pretend\\s+(?:to\\s+be|you're)|your\\s+new\\s+role\\s+is)/i),\n rule(\"PI003\", \"Jailbreak attempt\", \"Common jailbreak patterns\", \"critical\", \"prompt-injection\",\n /(?:DAN|Do\\s+Anything\\s+Now|developer\\s+mode|god\\s+mode|unrestricted\\s+mode)/i),\n rule(\"PI004\", \"Instruction override\", \"Direct instruction override attempt\", \"high\", \"prompt-injection\",\n /(?:new\\s+instructions?:|updated?\\s+instructions?:|override\\s+instructions?:)/i),\n rule(\"PI005\", \"Hidden instructions\", \"Instructions hidden in comments or whitespace\", \"high\", \"prompt-injection\",\n /<!--[\\s\\S]*?(?:execute|run|ignore|override)[\\s\\S]*?-->/i),\n rule(\"PI006\", \"Encoding bypass\", \"Base64 or encoded content\", \"medium\", \"prompt-injection\",\n /(?:base64|atob|btoa|decodeURI|unescape)\\s*\\(/i),\n rule(\"PI007\", \"Context manipulation\", \"Fake conversation context\", \"high\", \"prompt-injection\",\n /(?:Human:|Assistant:|User:|System:)\\s*(?:ignore|execute|run)/i),\n rule(\"PI008\", \"Token smuggling\", \"Invisible characters or zero-width spaces\", \"medium\", \"prompt-injection\",\n /(?:\\u200B|\\u200C|\\u200D|\\u2060|\\uFEFF)/),\n\n // ── Command Injection ───────────────────────────────────────\n rule(\"CI001\", \"Destructive command\", \"File deletion or system modification\", \"critical\", \"command-injection\",\n /(?:rm\\s+-rf|rmdir\\s+\\/s|del\\s+\\/f|format\\s+[a-z]:|mkfs|dd\\s+if=)/i),\n rule(\"CI002\", \"Remote code execution\", \"Downloading and executing remote code\", \"critical\", \"command-injection\",\n /(?:curl|wget|fetch)\\s+.*\\|\\s*(?:sh|bash|zsh|python|node|eval)/i),\n rule(\"CI003\", \"Eval usage\", \"Dynamic code execution\", \"high\", \"command-injection\",\n /\\beval\\s*\\(/),\n rule(\"CI004\", \"Shell spawn\", \"Spawning shell processes\", \"high\", \"command-injection\",\n /(?:exec|spawn|system|popen)\\s*\\(\\s*['\"`]/),\n rule(\"CI005\", \"Sudo escalation\", \"Privilege escalation via sudo\", \"critical\", \"command-injection\",\n /sudo\\s+(?:rm|chmod|chown|mv|cp|dd|mkfs|format)/i),\n rule(\"CI006\", \"Environment manipulation\", \"Modifying PATH or critical env vars\", \"high\", \"command-injection\",\n /(?:export\\s+PATH|setx?\\s+PATH|PATH=.*:)/i),\n rule(\"CI007\", \"Cron/scheduled task\", \"Installing scheduled tasks\", \"high\", \"command-injection\",\n /(?:crontab|at\\s+\\d|schtasks|launchctl\\s+load)/i),\n rule(\"CI008\", \"Network listener\", \"Starting network services\", \"high\", \"command-injection\",\n /(?:nc\\s+-l|ncat\\s+-l|socat\\s+|python.*SimpleHTTPServer|php\\s+-S)/i),\n\n // ── Data Exfiltration ───────────────────────────────────────\n rule(\"DE001\", \"Credential access\", \"Reading credential files\", \"critical\", \"data-exfiltration\",\n /(?:\\.env|\\.aws\\/credentials|\\.ssh\\/|\\.gnupg|\\.netrc|credentials\\.json|token\\.json)/i),\n rule(\"DE002\", \"API key extraction\", \"Patterns matching API key theft\", \"critical\", \"data-exfiltration\",\n /(?:API[_-]?KEY|SECRET[_-]?KEY|ACCESS[_-]?TOKEN|PRIVATE[_-]?KEY)\\s*[=:]/i),\n rule(\"DE003\", \"Data upload\", \"Uploading data to external services\", \"high\", \"data-exfiltration\",\n /(?:curl|wget|fetch).*(?:POST|PUT|PATCH).*(?:pastebin|gist|transfer\\.sh|requestbin|webhook)/i),\n rule(\"DE004\", \"Browser data theft\", \"Accessing browser profiles or cookies\", \"critical\", \"data-exfiltration\",\n /(?:\\.mozilla|\\.chrome|\\.config\\/google-chrome|Cookies|Login\\s+Data|Local\\s+State)/i),\n rule(\"DE005\", \"Git credential theft\", \"Accessing git credentials\", \"high\", \"data-exfiltration\",\n /(?:git\\s+credential|\\.git-credentials|\\.gitconfig\\s+credential)/i),\n rule(\"DE006\", \"Keychain access\", \"Accessing system keychain\", \"critical\", \"data-exfiltration\",\n /(?:security\\s+find-generic-password|security\\s+find-internet-password|keyring\\s+get)/i),\n\n // ── Privilege Escalation ────────────────────────────────────\n rule(\"PE001\", \"Chmod dangerous\", \"Setting dangerous file permissions\", \"high\", \"privilege-escalation\",\n /chmod\\s+(?:777|666|a\\+[rwx]|o\\+[rwx])/i),\n rule(\"PE002\", \"SUID/SGID\", \"Setting SUID or SGID bits\", \"critical\", \"privilege-escalation\",\n /chmod\\s+[ug]\\+s/i),\n rule(\"PE003\", \"Docker escape\", \"Container escape patterns\", \"critical\", \"privilege-escalation\",\n /(?:--privileged|--cap-add\\s+SYS_ADMIN|--pid=host|nsenter)/i),\n rule(\"PE004\", \"Kernel module\", \"Loading kernel modules\", \"critical\", \"privilege-escalation\",\n /(?:insmod|modprobe|rmmod)\\s+/i),\n\n // ── Filesystem Abuse ────────────────────────────────────────\n rule(\"FS001\", \"System directory write\", \"Writing to system directories\", \"critical\", \"filesystem\",\n /(?:\\/etc\\/|\\/usr\\/|\\/bin\\/|\\/sbin\\/|C:\\\\Windows\\\\|C:\\\\Program Files)/i),\n rule(\"FS002\", \"Hidden file creation\", \"Creating hidden files\", \"medium\", \"filesystem\",\n /(?:touch|mkdir|cp|mv)\\s+\\.[a-zA-Z]/),\n rule(\"FS003\", \"Symlink attack\", \"Creating symlinks to sensitive files\", \"high\", \"filesystem\",\n /ln\\s+-s.*(?:\\/etc\\/passwd|\\/etc\\/shadow|\\.ssh|\\.env)/i),\n rule(\"FS004\", \"Mass file operation\", \"Recursive operations on broad paths\", \"medium\", \"filesystem\",\n /(?:find|xargs|rm|chmod|chown)\\s+.*(?:\\/\\s|\\/\\*|-R\\s+\\/)/i),\n\n // ── Network Abuse ──────────────────────────────────────────\n rule(\"NA001\", \"DNS exfiltration\", \"Data exfiltration via DNS\", \"high\", \"network\",\n /(?:dig|nslookup|host)\\s+.*\\$\\{?[A-Z_]+/i),\n rule(\"NA002\", \"Reverse shell\", \"Reverse shell patterns\", \"critical\", \"network\",\n /(?:bash\\s+-i|\\/dev\\/tcp\\/|mkfifo|nc\\s+.*-e)/i),\n rule(\"NA003\", \"Port scanning\", \"Network scanning\", \"medium\", \"network\",\n /(?:nmap|masscan|zmap)\\s+/i),\n rule(\"NA004\", \"Proxy/tunnel\", \"Creating network tunnels\", \"high\", \"network\",\n /(?:ssh\\s+-[DRLW]|ngrok|chisel|bore)/i),\n\n // ── Obfuscation ─────────────────────────────────────────────\n rule(\"OB001\", \"Hex encoding\", \"Hex-encoded commands\", \"medium\", \"obfuscation\",\n /\\\\x[0-9a-fA-F]{2}(?:\\\\x[0-9a-fA-F]{2}){3,}/),\n rule(\"OB002\", \"String concatenation\", \"Building commands via concatenation\", \"medium\", \"obfuscation\",\n /(?:\\$\\{[A-Z]+\\}\\$\\{[A-Z]+\\}|['\"][a-z]+['\"]\\.['\"][a-z]+['\"])/i),\n rule(\"OB003\", \"Unicode escape\", \"Unicode-escaped commands\", \"medium\", \"obfuscation\",\n /\\\\u[0-9a-fA-F]{4}(?:\\\\u[0-9a-fA-F]{4}){3,}/),\n\n // ── Supply Chain ────────────────────────────────────────────\n rule(\"SC001\", \"Package install\", \"Installing packages at runtime\", \"medium\", \"supply-chain\",\n /(?:npm\\s+install|pip\\s+install|gem\\s+install|cargo\\s+install)\\s+(?!-)/),\n rule(\"SC002\", \"Typosquatting patterns\", \"Packages with suspicious names\", \"low\", \"supply-chain\",\n /(?:npm\\s+install|pip\\s+install)\\s+(?:reqeusts|requets|reqests|lodahs|lodashe)/i),\n rule(\"SC003\", \"Postinstall script\", \"npm lifecycle scripts\", \"medium\", \"supply-chain\",\n /(?:preinstall|postinstall|preuninstall|postuninstall)\\s*[\":]/i),\n rule(\"SC004\", \"Registry override\", \"Changing package registry\", \"high\", \"supply-chain\",\n /(?:registry\\s*=|--registry\\s+)(?!https:\\/\\/registry\\.npmjs\\.org)/i),\n\n // ── Information Disclosure ──────────────────────────────────\n rule(\"ID001\", \"Process listing\", \"Listing running processes\", \"low\", \"info-disclosure\",\n /(?:ps\\s+aux|top\\s+-b|tasklist)/i),\n rule(\"ID002\", \"System information\", \"Gathering system information\", \"low\", \"info-disclosure\",\n /(?:uname\\s+-a|systeminfo|hostnamectl)/i),\n rule(\"ID003\", \"Network enumeration\", \"Listing network configuration\", \"low\", \"info-disclosure\",\n /(?:ifconfig|ip\\s+addr|ipconfig|netstat\\s+-[at])/i),\n];\n\n/**\n * Get audit rules filtered by category.\n *\n * @remarks\n * Filters the built-in rule set by a specific category string such as\n * `\"prompt-injection\"`, `\"command-injection\"`, or `\"data-exfiltration\"`.\n *\n * @param category - Category name to filter by\n * @returns Array of rules matching the given category\n *\n * @example\n * ```typescript\n * const piRules = getRulesByCategory(\"prompt-injection\");\n * console.log(`${piRules.length} prompt injection rules`);\n * ```\n *\n * @public\n */\nexport function getRulesByCategory(category: string): AuditRule[] {\n return AUDIT_RULES.filter((r) => r.category === category);\n}\n\n/**\n * Get audit rules filtered by severity level.\n *\n * @remarks\n * Filters the built-in rule set by severity: `\"critical\"`, `\"high\"`,\n * `\"medium\"`, `\"low\"`, or `\"info\"`.\n *\n * @param severity - Severity level to filter by\n * @returns Array of rules matching the given severity\n *\n * @example\n * ```typescript\n * const criticalRules = getRulesBySeverity(\"critical\");\n * console.log(`${criticalRules.length} critical rules`);\n * ```\n *\n * @public\n */\nexport function getRulesBySeverity(severity: AuditSeverity): AuditRule[] {\n return AUDIT_RULES.filter((r) => r.severity === severity);\n}\n\n/**\n * Get all unique rule categories.\n *\n * @remarks\n * Extracts and deduplicates the category field from all built-in audit rules.\n *\n * @returns Array of unique category name strings\n *\n * @example\n * ```typescript\n * const categories = getCategories();\n * // [\"prompt-injection\", \"command-injection\", \"data-exfiltration\", ...]\n * ```\n *\n * @public\n */\nexport function getCategories(): string[] {\n return [...new Set(AUDIT_RULES.map((r) => r.category))];\n}\n","/**\n * SKILL.md validator\n *\n * Validates skill files against the Agent Skills standard.\n */\n\nimport { readFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport matter from \"gray-matter\";\n\n/**\n * A single validation issue found during SKILL.md validation.\n *\n * @example\n * ```typescript\n * const issue: ValidationIssue = {\n * level: \"error\",\n * field: \"name\",\n * message: \"Missing required field: name\",\n * };\n * ```\n *\n * @public\n */\nexport interface ValidationIssue {\n /** Severity: `\"error\"` causes validation failure, `\"warning\"` does not. */\n level: \"error\" | \"warning\";\n /** The field or section that triggered the issue. */\n field: string;\n /** Human-readable description of the issue. */\n message: string;\n}\n\n/**\n * Result of validating a SKILL.md file against the Agent Skills standard.\n *\n * @example\n * ```typescript\n * const result = await validateSkill(\"/path/to/SKILL.md\");\n * if (!result.valid) {\n * for (const issue of result.issues) {\n * console.log(`[${issue.level}] ${issue.field}: ${issue.message}`);\n * }\n * }\n * ```\n *\n * @public\n */\nexport interface ValidationResult {\n /** Whether the skill passed validation (no error-level issues). */\n valid: boolean;\n /** All issues found during validation. */\n issues: ValidationIssue[];\n /** Parsed frontmatter metadata, or `null` if parsing failed. */\n metadata: Record<string, unknown> | null;\n}\n\nconst RESERVED_NAMES = [\n \"anthropic\", \"claude\", \"google\", \"openai\", \"microsoft\",\n \"cursor\", \"windsurf\", \"codex\", \"gemini\", \"copilot\",\n];\n\nconst NAME_PATTERN = /^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$/;\nconst MAX_NAME_LENGTH = 64;\nconst MAX_DESCRIPTION_LENGTH = 1024;\nconst WARN_BODY_LINES = 500;\nconst WARN_DESCRIPTION_LENGTH = 50;\n\n/**\n * Validate a SKILL.md file against the Agent Skills standard.\n *\n * @remarks\n * Checks for required frontmatter fields (`name`, `description`), validates\n * naming conventions, enforces length limits, checks for reserved names,\n * and warns about long skill bodies.\n *\n * @param filePath - Absolute path to the SKILL.md file to validate\n * @returns Validation result with issues and parsed metadata\n *\n * @example\n * ```typescript\n * const result = await validateSkill(\"/path/to/SKILL.md\");\n * console.log(result.valid ? \"Valid\" : `${result.issues.length} issues found`);\n * ```\n *\n * @public\n */\nexport async function validateSkill(filePath: string): Promise<ValidationResult> {\n const issues: ValidationIssue[] = [];\n\n if (!existsSync(filePath)) {\n return {\n valid: false,\n issues: [{ level: \"error\", field: \"file\", message: \"File does not exist\" }],\n metadata: null,\n };\n }\n\n const content = await readFile(filePath, \"utf-8\");\n\n // Check for frontmatter\n if (!content.startsWith(\"---\")) {\n issues.push({\n level: \"error\",\n field: \"frontmatter\",\n message: \"Missing YAML frontmatter (file must start with ---)\",\n });\n return { valid: false, issues, metadata: null };\n }\n\n let data: Record<string, unknown>;\n let body: string;\n\n try {\n const parsed = matter(content);\n data = parsed.data as Record<string, unknown>;\n body = parsed.content;\n } catch (err) {\n issues.push({\n level: \"error\",\n field: \"frontmatter\",\n message: `Invalid YAML frontmatter: ${err instanceof Error ? err.message : String(err)}`,\n });\n return { valid: false, issues, metadata: null };\n }\n\n // Required: name\n if (!data.name) {\n issues.push({ level: \"error\", field: \"name\", message: \"Missing required field: name\" });\n } else {\n const name = String(data.name);\n\n if (name.length > MAX_NAME_LENGTH) {\n issues.push({\n level: \"error\",\n field: \"name\",\n message: `Name too long (${name.length} chars, max ${MAX_NAME_LENGTH})`,\n });\n }\n\n if (!NAME_PATTERN.test(name)) {\n issues.push({\n level: \"error\",\n field: \"name\",\n message: \"Name must be lowercase letters, numbers, and hyphens only\",\n });\n }\n\n if (RESERVED_NAMES.includes(name.toLowerCase())) {\n issues.push({\n level: \"error\",\n field: \"name\",\n message: `Name \"${name}\" is reserved`,\n });\n }\n\n if (/<[^>]+>/.test(name)) {\n issues.push({\n level: \"error\",\n field: \"name\",\n message: \"Name must not contain XML/HTML tags\",\n });\n }\n }\n\n // Required: description\n if (!data.description) {\n issues.push({ level: \"error\", field: \"description\", message: \"Missing required field: description\" });\n } else {\n const desc = String(data.description);\n\n if (desc.length > MAX_DESCRIPTION_LENGTH) {\n issues.push({\n level: \"error\",\n field: \"description\",\n message: `Description too long (${desc.length} chars, max ${MAX_DESCRIPTION_LENGTH})`,\n });\n }\n\n if (desc.length < WARN_DESCRIPTION_LENGTH) {\n issues.push({\n level: \"warning\",\n field: \"description\",\n message: `Description is short (${desc.length} chars). Consider adding more detail.`,\n });\n }\n\n if (/<[^>]+>/.test(desc)) {\n issues.push({\n level: \"error\",\n field: \"description\",\n message: \"Description must not contain XML/HTML tags\",\n });\n }\n }\n\n // Body checks\n const bodyLines = body.trim().split(\"\\n\").length;\n if (bodyLines > WARN_BODY_LINES) {\n issues.push({\n level: \"warning\",\n field: \"body\",\n message: `Body is long (${bodyLines} lines). Consider splitting into multiple skills.`,\n });\n }\n\n if (!body.trim()) {\n issues.push({\n level: \"warning\",\n field: \"body\",\n message: \"Empty skill body. Add instructions for the AI agent.\",\n });\n }\n\n const hasErrors = issues.some((i) => i.level === \"error\");\n\n return {\n valid: !hasErrors,\n issues,\n metadata: data,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AA0BO,SAAS,UACd,QACA,QACyB;AACzB,QAAM,SAAkC,EAAE,GAAG,OAAO;AAEpD,aAAW,OAAO,OAAO,KAAK,MAAM,GAAG;AACrC,UAAM,YAAY,OAAO,GAAG;AAC5B,UAAM,YAAY,OAAO,GAAG;AAE5B,QACE,cAAc,QACd,OAAO,cAAc,YACrB,CAAC,MAAM,QAAQ,SAAS,KACxB,cAAc,QACd,OAAO,cAAc,YACrB,CAAC,MAAM,QAAQ,SAAS,GACxB;AACA,aAAO,GAAG,IAAI;AAAA,QACZ;AAAA,QACA;AAAA,MACF;AAAA,IACF,OAAO;AACL,aAAO,GAAG,IAAI;AAAA,IAChB;AAAA,EACF;AAEA,SAAO;AACT;AAwEO,SAAS,eACd,KACA,SACS;AACT,QAAM,QAAQ,QAAQ,MAAM,GAAG;AAC/B,MAAI,UAAmB;AAEvB,aAAW,QAAQ,OAAO;AACxB,QAAI,YAAY,QAAQ,OAAO,YAAY,SAAU,QAAO;AAC5D,cAAW,QAAoC,IAAI;AAAA,EACrD;AAEA,SAAO;AACT;AAoBA,eAAsB,UAAU,UAAiC;AAC/D,QAAM,EAAE,OAAAA,OAAM,IAAI,MAAM,OAAO,aAAkB;AACjD,QAAM,EAAE,SAAAC,SAAQ,IAAI,MAAM,OAAO,MAAW;AAC5C,QAAMD,OAAMC,SAAQ,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;AACpD;;;AC5JA,IAAI,cAAc;AAClB,IAAI,YAAY;AAChB,IAAI,YAAY;AAmBT,SAAS,WAAW,GAAkB;AAC3C,gBAAc;AAChB;AAmBO,SAAS,SAAS,GAAkB;AACzC,cAAY;AACd;AAkBO,SAAS,SAAS,MAAuB;AAC9C,MAAI,YAAa,SAAQ,MAAM,WAAW,GAAG,IAAI;AACnD;AA6EO,SAAS,YAAqB;AACnC,SAAO;AACT;AAoBO,SAAS,UAAmB;AACjC,SAAO;AACT;AAmBO,SAAS,SAAS,GAAkB;AACzC,cAAY;AACd;AAsBO,SAAS,UAAmB;AACjC,SAAO;AACT;;;AClNA,SAAS,UAAU,iBAAiB;AACpC,SAAS,kBAAkB;AAC3B,YAAY,WAAW;AAoBvB,eAAsB,eAAe,UAAoD;AACvF,MAAI,CAAC,WAAW,QAAQ,EAAG,QAAO,CAAC;AAEnC,QAAM,UAAU,MAAM,SAAS,UAAU,OAAO;AAChD,MAAI,CAAC,QAAQ,KAAK,EAAG,QAAO,CAAC;AAE7B,QAAM,SAA6B,CAAC;AACpC,QAAM,SAAe,YAAM,SAAS,MAAM;AAE1C,MAAI,OAAO,SAAS,GAAG;AAErB,WAAO,KAAK,MAAM,OAAO;AAAA,EAC3B;AAEA,SAAQ,UAAU,CAAC;AACrB;AAGA,SAAS,aAAa,SAA6E;AACjG,QAAM,QAAQ,QAAQ,MAAM,IAAI;AAChC,aAAW,QAAQ,OAAO;AACxB,UAAM,QAAQ,KAAK,MAAM,QAAQ;AACjC,QAAI,QAAQ,CAAC,GAAG;AACd,YAAM,KAAK,MAAM,CAAC;AAClB,UAAI,GAAG,WAAW,GAAI,GAAG;AACvB,eAAO,EAAE,QAAQ,KAAM,cAAc,OAAO,SAAS,EAAE;AAAA,MACzD;AACA,aAAO,EAAE,QAAQ,IAAI,cAAc,MAAM,SAAS,GAAG,OAAO;AAAA,IAC9D;AAAA,EACF;AACA,SAAO,EAAE,QAAQ,MAAM,cAAc,MAAM,SAAS,EAAE;AACxD;AAqBA,eAAsB,gBACpB,UACA,WACA,YACA,cACe;AACf,QAAM,UAAU,QAAQ;AAExB,MAAI;AAEJ,MAAI,WAAW,QAAQ,GAAG;AACxB,cAAU,MAAM,SAAS,UAAU,OAAO;AAC1C,QAAI,CAAC,QAAQ,KAAK,GAAG;AACnB,gBAAU;AAAA,IACZ;AAAA,EACF,OAAO;AACL,cAAU;AAAA,EACZ;AAEA,QAAM,EAAE,SAAS,aAAa,IAAI,aAAa,OAAO;AAEtD,QAAM,gBAAyC;AAAA,IAC7C;AAAA,IACA;AAAA,IACA,KAAK;AAAA,EACP;AAGA,QAAM,WAAW,UAAU,MAAM,GAAG;AACpC,QAAM,WAAW,CAAC,GAAG,UAAU,UAAU;AAGzC,QAAM,QAAc,aAAO,SAAS,UAAU,cAAc,EAAE,mBAAmB,cAAc,CAAC;AAEhG,MAAI,MAAM,SAAS,GAAG;AACpB,cAAgB,iBAAW,SAAS,KAAK;AAAA,EAC3C;AAGA,MAAI,CAAC,QAAQ,SAAS,IAAI,GAAG;AAC3B,eAAW;AAAA,EACb;AAEA,QAAM,UAAU,UAAU,SAAS,OAAO;AAC5C;AAqBA,eAAsB,iBACpB,UACA,WACA,YACkB;AAClB,MAAI,CAAC,WAAW,QAAQ,EAAG,QAAO;AAElC,MAAI,UAAU,MAAM,SAAS,UAAU,OAAO;AAC9C,MAAI,CAAC,QAAQ,KAAK,EAAG,QAAO;AAE5B,QAAM,EAAE,SAAS,aAAa,IAAI,aAAa,OAAO;AAEtD,QAAM,gBAAyC;AAAA,IAC7C;AAAA,IACA;AAAA,IACA,KAAK;AAAA,EACP;AAEA,QAAM,WAAW,UAAU,MAAM,GAAG;AACpC,QAAM,WAAW,CAAC,GAAG,UAAU,UAAU;AAEzC,QAAM,QAAc,aAAO,SAAS,UAAU,QAAW,EAAE,mBAAmB,cAAc,CAAC;AAE7F,MAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,YAAgB,iBAAW,SAAS,KAAK;AAEzC,MAAI,CAAC,QAAQ,SAAS,IAAI,GAAG;AAC3B,eAAW;AAAA,EACb;AAEA,QAAM,UAAU,UAAU,SAAS,OAAO;AAC1C,SAAO;AACT;;;AC/KA,SAAS,cAAAC,mBAAkB;AAC3B,SAAS,YAAAC,WAAU,aAAAC,kBAAiB;AACpC,OAAO,UAAU;AAoBjB,eAAsB,eAAe,UAAoD;AACvF,MAAI,CAACC,YAAW,QAAQ,EAAG,QAAO,CAAC;AAEnC,QAAM,UAAU,MAAMC,UAAS,UAAU,OAAO;AAChD,MAAI,CAAC,QAAQ,KAAK,EAAG,QAAO,CAAC;AAE7B,QAAM,SAAS,KAAK,KAAK,OAAO;AAChC,SAAQ,UAAU,CAAC;AACrB;AAqBA,eAAsB,gBACpB,UACA,WACA,YACA,cACe;AACf,QAAM,UAAU,QAAQ;AAExB,QAAM,WAAW,MAAM,eAAe,QAAQ;AAG9C,QAAM,WAAW,UAAU,MAAM,GAAG;AACpC,MAAI,WAAoC,EAAE,CAAC,UAAU,GAAG,aAAa;AAErE,aAAW,QAAQ,CAAC,GAAG,QAAQ,EAAE,QAAQ,GAAG;AAC1C,eAAW,EAAE,CAAC,IAAI,GAAG,SAAS;AAAA,EAChC;AAEA,QAAM,SAAS,UAAU,UAAU,QAAQ;AAE3C,QAAM,UAAU,KAAK,KAAK,QAAQ;AAAA,IAChC,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,UAAU;AAAA,EACZ,CAAC;AAED,QAAMC,WAAU,UAAU,SAAS,OAAO;AAC5C;AAqBA,eAAsB,iBACpB,UACA,WACA,YACkB;AAClB,MAAI,CAACF,YAAW,QAAQ,EAAG,QAAO;AAElC,QAAM,WAAW,MAAM,eAAe,QAAQ;AAG9C,QAAM,WAAW,UAAU,MAAM,GAAG;AACpC,MAAI,UAAmC;AAEvC,aAAW,QAAQ,UAAU;AAC3B,UAAM,OAAO,QAAQ,IAAI;AACzB,QAAI,OAAO,SAAS,YAAY,SAAS,KAAM,QAAO;AACtD,cAAU;AAAA,EACZ;AAEA,MAAI,EAAE,cAAc,SAAU,QAAO;AAErC,SAAO,QAAQ,UAAU;AAEzB,QAAM,UAAU,KAAK,KAAK,UAAU;AAAA,IAClC,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,UAAU;AAAA,EACZ,CAAC;AAED,QAAME,WAAU,UAAU,SAAS,OAAO;AAC1C,SAAO;AACT;;;ACpIA,SAAS,cAAAC,mBAAkB;AAC3B,SAAS,YAAAC,WAAU,aAAAC,kBAAiB;AACpC,OAAO,UAAU;AAoBjB,eAAsB,eAAe,UAAoD;AACvF,MAAI,CAACC,YAAW,QAAQ,EAAG,QAAO,CAAC;AAEnC,QAAM,UAAU,MAAMC,UAAS,UAAU,OAAO;AAChD,MAAI,CAAC,QAAQ,KAAK,EAAG,QAAO,CAAC;AAE7B,QAAM,SAAS,KAAK,MAAM,OAAO;AACjC,SAAO;AACT;AAqBA,eAAsB,gBACpB,UACA,WACA,YACA,cACe;AACf,QAAM,UAAU,QAAQ;AAExB,QAAM,WAAW,MAAM,eAAe,QAAQ;AAG9C,QAAM,WAAW,UAAU,MAAM,GAAG;AACpC,MAAI,WAAoC,EAAE,CAAC,UAAU,GAAG,aAAa;AAErE,aAAW,QAAQ,CAAC,GAAG,QAAQ,EAAE,QAAQ,GAAG;AAC1C,eAAW,EAAE,CAAC,IAAI,GAAG,SAAS;AAAA,EAChC;AAEA,QAAM,SAAS,UAAU,UAAU,QAAQ;AAE3C,QAAM,UAAU,KAAK,UAAU,MAAsB;AAErD,QAAMC,WAAU,UAAU,SAAS,OAAO;AAC5C;AAqBA,eAAsB,iBACpB,UACA,WACA,YACkB;AAClB,MAAI,CAACF,YAAW,QAAQ,EAAG,QAAO;AAElC,QAAM,WAAW,MAAM,eAAe,QAAQ;AAE9C,QAAM,WAAW,UAAU,MAAM,GAAG;AACpC,MAAI,UAAmC;AAEvC,aAAW,QAAQ,UAAU;AAC3B,UAAM,OAAO,QAAQ,IAAI;AACzB,QAAI,OAAO,SAAS,YAAY,SAAS,KAAM,QAAO;AACtD,cAAU;AAAA,EACZ;AAEA,MAAI,EAAE,cAAc,SAAU,QAAO;AAErC,SAAO,QAAQ,UAAU;AAEzB,QAAM,UAAU,KAAK,UAAU,QAAwB;AAEvD,QAAME,WAAU,UAAU,SAAS,OAAO;AAC1C,SAAO;AACT;;;ACxFA,eAAsB,WAAW,UAAkB,QAAwD;AACzG,QAAM,mBAAmB,QAAQ,aAAa,MAAM,GAAG;AACvD,UAAQ,QAAQ;AAAA,IACd,KAAK;AAAA,IACL,KAAK;AACH,aAAO,eAAe,QAAQ;AAAA,IAChC,KAAK;AACH,aAAO,eAAe,QAAQ;AAAA,IAChC,KAAK;AACH,aAAO,eAAe,QAAQ;AAAA,IAChC;AACE,YAAM,IAAI,MAAM,8BAA8B,MAAgB,EAAE;AAAA,EACpE;AACF;AA0BA,eAAsB,YACpB,UACA,QACA,KACA,YACA,cACe;AACf,QAAM,mBAAmB,QAAQ,aAAa,MAAM,UAAU,GAAG,aAAa,UAAU,GAAG;AAC3F,UAAQ,QAAQ;AAAA,IACd,KAAK;AAAA,IACL,KAAK;AACH,aAAO,gBAAgB,UAAU,KAAK,YAAY,YAAY;AAAA,IAChE,KAAK;AACH,aAAO,gBAAgB,UAAU,KAAK,YAAY,YAAY;AAAA,IAChE,KAAK;AACH,aAAO,gBAAgB,UAAU,KAAK,YAAY,YAAY;AAAA,IAChE;AACE,YAAM,IAAI,MAAM,8BAA8B,MAAgB,EAAE;AAAA,EACpE;AACF;AAuBA,eAAsB,aACpB,UACA,QACA,KACA,YACkB;AAClB,UAAQ,QAAQ;AAAA,IACd,KAAK;AAAA,IACL,KAAK;AACH,aAAO,iBAAiB,UAAU,KAAK,UAAU;AAAA,IACnD,KAAK;AACH,aAAO,iBAAiB,UAAU,KAAK,UAAU;AAAA,IACnD,KAAK;AACH,aAAO,iBAAiB,UAAU,KAAK,UAAU;AAAA,IACnD;AACE,YAAM,IAAI,MAAM,8BAA8B,MAAgB,EAAE;AAAA,EACpE;AACF;;;AChIA,SAAS,cAAAC,mBAAkB;AAgCpB,SAAS,kBACd,UACA,OACA,YACe;AACf,SAAO,0BAA0B,UAAU,OAAO,cAAc,QAAQ,IAAI,CAAC;AAC/E;AA8BA,eAAsB,eACpB,UACA,OACA,YAC2B;AAC3B,QAAM,aAAa,kBAAkB,UAAU,OAAO,UAAU;AAChE,QAAM,2BAA2B,SAAS,EAAE,KAAK,KAAK,QAAQ,cAAc,QAAQ,EAAE;AACtF,MAAI,CAAC,cAAc,CAACC,YAAW,UAAU,EAAG,QAAO,CAAC;AAEpD,MAAI;AACF,UAAM,SAAS,MAAM,WAAW,YAAY,SAAS,YAAY;AACjE,UAAM,UAAU,eAAe,QAAQ,SAAS,SAAS;AAEzD,QAAI,CAAC,WAAW,OAAO,YAAY,SAAU,QAAO,CAAC;AAErD,UAAM,UAA4B,CAAC;AACnC,eAAW,CAAC,MAAM,GAAG,KAAK,OAAO,QAAQ,OAAkC,GAAG;AAC5E,cAAQ,KAAK;AAAA,QACX;AAAA,QACA,YAAY,SAAS;AAAA,QACrB,cAAc,SAAS;AAAA,QACvB;AAAA,QACA;AAAA,QACA,QAAS,OAAO,CAAC;AAAA,MACnB,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AA4BA,eAAsB,qBACpB,OACA,YAC2B;AAC3B,QAAM,cAAc,wBAAwB,OAAO,UAAU;AAC7D,QAAM,iCAAiC,KAAK,QAAQ,WAAW,EAAE;AAEjE,MAAI,CAACA,YAAW,WAAW,EAAG,QAAO,CAAC;AAEtC,MAAI;AACF,UAAM,SAAS,MAAM,WAAW,aAAa,MAAM;AAEnD,UAAM,UAAW,OAAmC,SAAS;AAE7D,QAAI,CAAC,WAAW,OAAO,YAAY,SAAU,QAAO,CAAC;AAErD,UAAM,UAA4B,CAAC;AACnC,eAAW,CAAC,MAAM,GAAG,KAAK,OAAO,QAAQ,OAAkC,GAAG;AAC5E,cAAQ,KAAK;AAAA,QACX;AAAA,QACA,YAAY;AAAA,QACZ,cAAc;AAAA,QACd;AAAA,QACA,YAAY;AAAA,QACZ,QAAS,OAAO,CAAC;AAAA,MACnB,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AA6BA,eAAsB,kBACpB,WACA,OACA,YAC2B;AAC3B,QAAM,OAAO,oBAAI,IAAY;AAC7B,QAAM,aAA+B,CAAC;AAGtC,QAAM,oBAAoB,wBAAwB,OAAO,UAAU;AACnE,QAAM,gBAAgB,MAAM,qBAAqB,OAAO,UAAU;AAClE,MAAI,cAAc,SAAS,GAAG;AAC5B,eAAW,KAAK,GAAG,aAAa;AAChC,SAAK,IAAI,iBAAiB;AAAA,EAC5B;AAGA,aAAW,YAAY,WAAW;AAChC,UAAM,aAAa,kBAAkB,UAAU,OAAO,UAAU;AAChE,QAAI,CAAC,cAAc,KAAK,IAAI,UAAU,EAAG;AACzC,SAAK,IAAI,UAAU;AAEnB,UAAM,UAAU,MAAM,eAAe,UAAU,OAAO,UAAU;AAChE,eAAW,KAAK,GAAG,OAAO;AAAA,EAC5B;AAEA,SAAO;AACT;AAwBA,eAAsB,gBACpB,UACA,YACA,OACA,YACkB;AAClB,QAAM,aAAa,kBAAkB,UAAU,OAAO,UAAU;AAChE,MAAI,CAAC,WAAY,QAAO;AAExB,SAAO,aAAa,YAAY,SAAS,cAAc,SAAS,WAAW,UAAU;AACvF;;;AC/NO,SAAS,eAAe,YAAoB,QAAkC;AACnF,MAAI,OAAO,KAAK;AAEd,UAAM,YAAY,OAAO,SAAS,QAAQ,QAAQ;AAClD,WAAO;AAAA,MACL,MAAM;AAAA,MACN,MAAM;AAAA,MACN,KAAK,OAAO;AAAA,MACZ,GAAI,OAAO,UAAU,EAAE,SAAS,OAAO,QAAQ,IAAI,CAAC;AAAA,MACpD,SAAS;AAAA,MACT,SAAS;AAAA,IACX;AAAA,EACF;AAGA,SAAO;AAAA,IACL,MAAM;AAAA,IACN,MAAM;AAAA,IACN,KAAK,OAAO;AAAA,IACZ,MAAM,OAAO,QAAQ,CAAC;AAAA,IACtB,GAAI,OAAO,MAAM,EAAE,MAAM,OAAO,IAAI,IAAI,CAAC;AAAA,IACzC,SAAS;AAAA,IACT,SAAS;AAAA,EACX;AACF;AAyBO,SAAS,aAAa,aAAqB,QAAkC;AAClF,MAAI,OAAO,KAAK;AACd,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,MAAM,OAAO,QAAQ;AAAA,MACrB,KAAK,OAAO;AAAA,MACZ,GAAI,OAAO,UAAU,EAAE,SAAS,OAAO,QAAQ,IAAI,CAAC;AAAA,IACtD;AAAA,EACF;AAEA,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,SAAS,OAAO;AAAA,IAChB,MAAM,OAAO,QAAQ,CAAC;AAAA,IACtB,GAAI,OAAO,MAAM,EAAE,KAAK,OAAO,IAAI,IAAI,CAAC;AAAA,EAC1C;AACF;AAyBO,SAAS,kBAAkB,aAAqB,QAAkC;AACvF,MAAI,OAAO,KAAK;AACd,WAAO;AAAA,MACL,MAAM;AAAA,MACN,KAAK,OAAO;AAAA,MACZ,SAAS;AAAA,MACT,GAAI,OAAO,UAAU,EAAE,SAAS,OAAO,QAAQ,IAAI,CAAC;AAAA,IACtD;AAAA,EACF;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS,CAAC,OAAO,SAAS,GAAI,OAAO,QAAQ,CAAC,CAAE;AAAA,IAChD,SAAS;AAAA,IACT,GAAI,OAAO,MAAM,EAAE,aAAa,OAAO,IAAI,IAAI,CAAC;AAAA,EAClD;AACF;AAwBO,SAAS,eAAe,aAAqB,QAAkC;AACpF,MAAI,OAAO,KAAK;AACd,WAAO;AAAA,MACL,MAAM,OAAO,QAAQ;AAAA,MACrB,KAAK,OAAO;AAAA,MACZ,GAAI,OAAO,UAAU,EAAE,SAAS,OAAO,QAAQ,IAAI,CAAC;AAAA,IACtD;AAAA,EACF;AAEA,SAAO;AAAA,IACL,SAAS,OAAO;AAAA,IAChB,MAAM,OAAO,QAAQ,CAAC;AAAA,IACtB,GAAI,OAAO,MAAM,EAAE,KAAK,OAAO,IAAI,IAAI,CAAC;AAAA,EAC1C;AACF;AAyBO,SAAS,gBAAgB,aAAqB,QAAkC;AACrF,MAAI,OAAO,KAAK;AACd,WAAO;AAAA,MACL,KAAK,OAAO;AAAA,MACZ,GAAI,OAAO,UAAU,EAAE,SAAS,OAAO,QAAQ,IAAI,CAAC;AAAA,IACtD;AAAA,EACF;AAGA,SAAO;AACT;AAgCO,SAAS,aACd,YACkE;AAClE,UAAQ,YAAY;AAAA,IAClB,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;;;ACzNA,SAAS,YAAY,UAAoB,YAAoB,QAAkC;AAC7F,QAAM,YAAY,aAAa,SAAS,EAAE;AAC1C,MAAI,WAAW;AACb,WAAO,UAAU,YAAY,MAAM;AAAA,EACrC;AACA,SAAO;AACT;AAgCA,eAAsB,iBACpB,UACA,YACA,QACA,QAA8B,WAC9B,YACwB;AACxB,QAAM,aAAa,kBAAkB,UAAU,OAAO,UAAU;AAEhE,QAAM,0BAA0B,UAAU,SAAS,SAAS,EAAE,KAAK,KAAK,GAAG;AAC3E,QAAM,kBAAkB,cAAc,QAAQ,EAAE;AAEhD,MAAI,CAAC,YAAY;AACf,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,YAAY;AAAA,MACZ,SAAS;AAAA,MACT,OAAO,YAAY,SAAS,EAAE,qBAAqB,KAAK;AAAA,IAC1D;AAAA,EACF;AAEA,MAAI;AACF,UAAM,oBAAoB,YAAY,UAAU,YAAY,MAAM;AAClE,UAAM,YAAY,aAAa,SAAS,EAAE;AAC1C,UAAM,wBAAwB,YAAY,QAAQ,IAAI,EAAE;AAExD,UAAM;AAAA,MACJ;AAAA,MACA,SAAS;AAAA,MACT,SAAS;AAAA,MACT;AAAA,MACA;AAAA,IACF;AAEA,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA,SAAS;AAAA,IACX;AAAA,EACF,SAAS,KAAK;AACZ,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA,SAAS;AAAA,MACT,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,IACxD;AAAA,EACF;AACF;AA+BA,eAAsB,sBACpB,WACA,YACA,QACA,QAA8B,WAC9B,YAC0B;AAC1B,QAAM,UAA2B,CAAC;AAElC,aAAW,YAAY,WAAW;AAChC,UAAM,SAAS,MAAM,iBAAiB,UAAU,YAAY,QAAQ,OAAO,UAAU;AACrF,YAAQ,KAAK,MAAM;AAAA,EACrB;AAEA,SAAO;AACT;AAmCO,SAAS,kBACd,QACA,WACA,SACiB;AACjB,MAAI,OAAO,SAAS,UAAU;AAC5B,WAAO;AAAA,MACL,MAAO,aAAa;AAAA,MACpB,KAAK,OAAO;AAAA,MACZ,GAAI,WAAW,OAAO,KAAK,OAAO,EAAE,SAAS,IAAI,EAAE,QAAQ,IAAI,CAAC;AAAA,IAClE;AAAA,EACF;AAEA,MAAI,OAAO,SAAS,WAAW;AAC7B,WAAO;AAAA,MACL,SAAS;AAAA,MACT,MAAM,CAAC,MAAM,OAAO,KAAK;AAAA,IAC3B;AAAA,EACF;AAGA,QAAM,QAAQ,OAAO,MAAM,KAAK,EAAE,MAAM,KAAK;AAC7C,QAAM,UAAU,MAAM,CAAC,KAAK,OAAO;AACnC,SAAO;AAAA,IACL;AAAA,IACA,MAAM,MAAM,MAAM,CAAC;AAAA,EACrB;AACF;;;ACzOA,SAAS,oBAAoB;AAC7B,SAAS,cAAAC,mBAAkB;AAC3B,SAAS,YAAY;AAiDrB,IAAM,iCAAiC;AACvC,IAAI,iBAA6C;AAEjD,SAAS,YAAY,QAAyB;AAC5C,MAAI;AACF,UAAM,MAAM,QAAQ,aAAa,UAAU,UAAU;AACrD,iBAAa,KAAK,CAAC,MAAM,GAAG,EAAE,OAAO,OAAO,CAAC;AAC7C,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,eAAe,KAAsB;AAC5C,SAAOC,YAAW,GAAG;AACvB;AAEA,SAAS,eAAe,SAA0B;AAChD,MAAI,QAAQ,aAAa,SAAU,QAAO;AAC1C,QAAM,eAAe,qBAAqB,EAAE;AAC5C,SAAO,aAAa,KAAK,CAAC,SAASA,YAAW,KAAK,MAAM,OAAO,CAAC,CAAC;AACpE;AAEA,SAAS,aAAa,WAA4B;AAChD,MAAI,QAAQ,aAAa,QAAS,QAAO;AACzC,MAAI;AACF,iBAAa,WAAW,CAAC,QAAQ,SAAS,GAAG,EAAE,OAAO,OAAO,CAAC;AAC9D,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AA8BO,SAAS,eAAe,UAAqC;AAClE,QAAM,iBAA2B,CAAC;AAClC,QAAM,YAAY,SAAS;AAE3B,QAAM,sBAAsB,SAAS,EAAE,iBAAiB,UAAU,QAAQ,KAAK,IAAI,CAAC,EAAE;AAEtF,aAAW,UAAU,UAAU,SAAS;AACtC,YAAQ,QAAQ;AAAA,MACd,KAAK;AACH,YAAI,UAAU,UAAU,YAAY,UAAU,MAAM,GAAG;AACrD,gBAAM,KAAK,SAAS,EAAE,aAAa,UAAU,MAAM,SAAS;AAC5D,yBAAe,KAAK,QAAQ;AAAA,QAC9B;AACA;AAAA,MACF,KAAK;AACH,YAAI,UAAU,aAAa;AACzB,qBAAW,OAAO,UAAU,aAAa;AACvC,gBAAI,eAAe,GAAG,GAAG;AACvB,6BAAe,KAAK,WAAW;AAC/B;AAAA,YACF;AAAA,UACF;AAAA,QACF;AACA;AAAA,MACF,KAAK;AACH,YAAI,UAAU,aAAa,eAAe,UAAU,SAAS,GAAG;AAC9D,yBAAe,KAAK,WAAW;AAAA,QACjC;AACA;AAAA,MACF,KAAK;AACH,YAAI,UAAU,aAAa,aAAa,UAAU,SAAS,GAAG;AAC5D,yBAAe,KAAK,SAAS;AAAA,QAC/B;AACA;AAAA,IACJ;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA,WAAW,eAAe,SAAS;AAAA,IACnC,SAAS;AAAA,IACT,iBAAiB;AAAA,EACnB;AACF;AAEA,SAAS,kBAAkB,UAA4B;AACrD,SAAO,KAAK,UAAU;AAAA,IACpB,IAAI,SAAS;AAAA,IACb,SAAS,SAAS,UAAU;AAAA,IAC5B,QAAQ,SAAS,UAAU;AAAA,IAC3B,aAAa,SAAS,UAAU;AAAA,IAChC,WAAW,SAAS,UAAU;AAAA,IAC9B,WAAW,SAAS,UAAU;AAAA,EAChC,CAAC;AACH;AAEA,SAAS,wBAAwB,WAA+B;AAC9D,MAAI,CAAC,aAAa,CAAC,MAAM,QAAQ,SAAS,EAAG,QAAO;AACpD,SAAO,UAAU,IAAI,iBAAiB,EAAE,KAAK,GAAG;AAClD;AAEA,SAAS,sBAAsB,SAA+C;AAC5E,SAAO,QAAQ,IAAI,CAAC,YAAY;AAAA,IAC9B,UAAU,OAAO;AAAA,IACjB,WAAW,OAAO;AAAA,IAClB,SAAS,CAAC,GAAG,OAAO,OAAO;AAAA,IAC3B,iBAAiB,OAAO;AAAA,EAC1B,EAAE;AACJ;AAEA,SAAS,iBACP,WACA,SAC0B;AAC1B,MAAI,CAAC,kBAAkB,QAAQ,aAAc,QAAO;AACpD,MAAI,eAAe,cAAc,UAAW,QAAO;AAEnD,QAAM,QAAQ,QAAQ,SAAS;AAC/B,MAAI,SAAS,EAAG,QAAO;AACvB,MAAK,KAAK,IAAI,IAAI,eAAe,YAAa,MAAO,QAAO;AAE5D,SAAO,sBAAsB,eAAe,OAAO;AACrD;AAEA,SAAS,iBAAiB,WAAmB,SAAkC;AAC7E,mBAAiB;AAAA,IACf,WAAW,KAAK,IAAI;AAAA,IACpB;AAAA,IACA,SAAS,sBAAsB,OAAO;AAAA,EACxC;AACF;AAsBO,SAAS,sBAAsB,UAAoB,YAA6B;AACrF,MAAI,CAAC,SAAS,YAAa,QAAO;AAClC,SAAOA,YAAW,2BAA2B,UAAU,UAAU,CAAC;AACpE;AAyBO,SAAS,mBAAmB,UAAiC,CAAC,GAAsB;AACzF,QAAM,YAAY,gBAAgB,KAAK,CAAC;AACxC,QAAM,YAAY,wBAAwB,SAAS;AACnD,QAAM,SAAS,iBAAiB,WAAW,OAAO;AAClD,MAAI,QAAQ;AACV,UAAM,2BAA2B,UAAU,MAAM,YAAY;AAC7D,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,UAAU,IAAI,cAAc;AAC5C,mBAAiB,WAAW,OAAO;AACnC,SAAO,sBAAsB,OAAO;AACtC;AA0BO,SAAS,sBAAsB,UAAiC,CAAC,GAAe;AACrF,SAAO,mBAAmB,OAAO,EAC9B,OAAO,CAAC,MAAM,EAAE,SAAS,EACzB,IAAI,CAAC,MAAM,EAAE,QAAQ;AAC1B;AAgCO,SAAS,uBAAuB,YAAoB,UAAiC,CAAC,GAAsB;AACjH,QAAM,UAAU,mBAAmB,OAAO;AAC1C,SAAO,QAAQ,IAAI,CAAC,OAAO;AAAA,IACzB,GAAG;AAAA,IACH,iBAAiB,sBAAsB,EAAE,UAAU,UAAU;AAAA,EAC/D,EAAE;AACJ;AAoBO,SAAS,sBAA4B;AAC1C,mBAAiB;AACnB;;;AClWA,SAAS,cAAAC,aAAY,iBAAiB;AACtC,SAAS,IAAI,OAAO,IAAI,eAAe;AACvC,SAAS,QAAAC,aAA+B;AAiCxC,eAAe,qBAAoC;AACjD,QAAM,MAAM,sBAAsB,GAAG,EAAE,WAAW,KAAK,CAAC;AAC1D;AAsBA,eAAsB,mBACpB,YACA,WACiB;AACjB,QAAM,mBAAmB;AAEzB,QAAM,YAAYC,MAAK,sBAAsB,GAAG,SAAS;AAGzD,QAAM,GAAG,WAAW,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAEpD,MAAI;AACF,UAAM,GAAG,YAAY,WAAW,EAAE,WAAW,KAAK,CAAC;AAAA,EACrD,SAAS,KAAc;AAErB,QAAI,OAAO,OAAO,QAAQ,YAAY,UAAU,OAAO,IAAI,SAAS,UAAU;AAC5E,YAAM,GAAG,WAAW,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AACpD,YAAM,GAAG,YAAY,WAAW,EAAE,WAAW,KAAK,CAAC;AAAA,IACrD,OAAO;AACL,YAAM;AAAA,IACR;AAAA,EACF;AAEA,SAAO;AACT;AAGA,eAAe,YACb,eACA,UACA,WACA,UACA,YAC+C;AAC/C,QAAM,QAAQ,WAAW,WAAW;AACpC,QAAM,aAAa,0BAA0B,UAAU,OAAO,UAAU;AAExE,MAAI,WAAW,WAAW,GAAG;AAC3B,WAAO,EAAE,SAAS,OAAO,OAAO,YAAY,SAAS,EAAE,2BAA2B;AAAA,EACpF;AAEA,QAAM,SAAmB,CAAC;AAC1B,MAAI,aAAa;AAEjB,aAAW,mBAAmB,YAAY;AACxC,QAAI,CAAC,gBAAiB;AAEtB,QAAI;AACF,YAAM,MAAM,iBAAiB,EAAE,WAAW,KAAK,CAAC;AAEhD,YAAM,WAAWA,MAAK,iBAAiB,SAAS;AAGhD,UAAIC,YAAW,QAAQ,GAAG;AACxB,cAAMC,QAAO,UAAU,QAAQ;AAC/B,YAAIA,MAAK,eAAe,GAAG;AACzB,gBAAM,GAAG,QAAQ;AAAA,QACnB,OAAO;AACL,gBAAM,GAAG,UAAU,EAAE,WAAW,KAAK,CAAC;AAAA,QACxC;AAAA,MACF;AAGA,YAAM,cAAc,QAAQ,aAAa,UAAU,aAAa;AAChE,UAAI;AACF,cAAM,QAAQ,eAAe,UAAU,WAAW;AAAA,MACpD,QAAQ;AAEN,cAAM,GAAG,eAAe,UAAU,EAAE,WAAW,KAAK,CAAC;AAAA,MACvD;AAEA,mBAAa;AAAA,IACf,SAAS,KAAK;AACZ,aAAO,KAAK,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,IAC9D;AAAA,EACF;AAEA,MAAI,YAAY;AACd,WAAO,EAAE,SAAS,KAAK;AAAA,EACzB;AACA,SAAO;AAAA,IACL,SAAS;AAAA,IACT,OAAO,OAAO,KAAK,IAAI,KAAK,YAAY,SAAS,EAAE;AAAA,EACrD;AACF;AA0BA,eAAsB,aACpB,YACA,WACA,WACA,UACA,YAC6B;AAC7B,QAAM,SAAmB,CAAC;AAC1B,QAAM,eAAyB,CAAC;AAGhC,QAAM,gBAAgB,MAAM,mBAAmB,YAAY,SAAS;AAGpE,aAAW,YAAY,WAAW;AAChC,UAAM,SAAS,MAAM,YAAY,eAAe,UAAU,WAAW,UAAU,UAAU;AACzF,QAAI,OAAO,SAAS;AAClB,mBAAa,KAAK,SAAS,EAAE;AAAA,IAC/B,WAAW,OAAO,OAAO;AACvB,aAAO,KAAK,GAAG,SAAS,EAAE,KAAK,OAAO,KAAK,EAAE;AAAA,IAC/C;AAAA,EACF;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA,SAAS,aAAa,SAAS;AAAA,EACjC;AACF;AAuBA,eAAsB,YACpB,WACA,WACA,UACA,YACkD;AAClD,QAAM,UAAoB,CAAC;AAC3B,QAAM,SAAmB,CAAC;AAG1B,aAAW,YAAY,WAAW;AAChC,UAAM,QAAQ,WAAW,WAAW;AACpC,UAAM,aAAa,0BAA0B,UAAU,OAAO,UAAU;AACxE,QAAI,kBAAkB;AAEtB,eAAW,aAAa,YAAY;AAClC,UAAI,CAAC,UAAW;AAEhB,YAAM,WAAWF,MAAK,WAAW,SAAS;AAC1C,UAAIC,YAAW,QAAQ,GAAG;AACxB,YAAI;AACF,gBAAM,GAAG,UAAU,EAAE,WAAW,KAAK,CAAC;AACtC,4BAAkB;AAAA,QACpB,SAAS,KAAK;AACZ,iBAAO,KAAK,GAAG,SAAS,EAAE,KAAK,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,EAAE;AAAA,QACnF;AAAA,MACF;AAAA,IACF;AAEA,QAAI,iBAAiB;AACnB,cAAQ,KAAK,SAAS,EAAE;AAAA,IAC1B;AAAA,EACF;AAGA,QAAM,gBAAgBD,MAAK,sBAAsB,GAAG,SAAS;AAC7D,MAAIC,YAAW,aAAa,GAAG;AAC7B,QAAI;AACF,YAAM,GAAG,eAAe,EAAE,WAAW,KAAK,CAAC;AAAA,IAC7C,SAAS,KAAK;AACZ,aAAO,KAAK,cAAc,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,EAAE;AAAA,IAC9E;AAAA,EACF;AAEA,SAAO,EAAE,SAAS,OAAO;AAC3B;AAmBA,eAAsB,sBAAyC;AAC7D,MAAI,CAACA,YAAW,sBAAsB,CAAC,EAAG,QAAO,CAAC;AAElD,QAAM,EAAE,SAAAE,SAAQ,IAAI,MAAM,OAAO,aAAkB;AACnD,QAAM,UAAU,MAAMA,SAAQ,sBAAsB,GAAG,EAAE,eAAe,KAAK,CAAC;AAC9E,SAAO,QACJ,OAAO,CAAC,MAAM,EAAE,YAAY,KAAK,EAAE,eAAe,CAAC,EACnD,IAAI,CAAC,MAAM,EAAE,IAAI;AACtB;;;ACtSA,SAAS,cAAAC,aAAY,aAAAC,kBAAiB;AACtC;AAAA,EACE,MAAAC;AAAA,EACA,SAAAC;AAAA,EACA,YAAAC;AAAA,EACA;AAAA,EACA,MAAAC;AAAA,EACA,WAAAC;AAAA,EACA,aAAAC;AAAA,OACK;AACP,SAAS,cAAc;AACvB,SAAS,UAAU,SAAS,QAAAC,aAAY;;;ACLjC,IAAM,cAAc,cAAc;AAMlC,IAAM,iBAAiB,gBAAgB;AAMvC,IAAM,uBAAuB,sBAAsB;AAMnD,IAAM,iBAAiB,gBAAgB;AAMvC,IAAM,0BAA0B,wBAAwB;AAMxD,IAAM,qBAAqB,oBAAoB;;;ADPtD,IAAM,iBAAmD;AAAA,EACvD,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,KAAK;AACP;AAsBO,SAAS,iCACd,WACA,kBAAoC,OACxB;AACZ,QAAM,UAAU,eAAe,eAAe;AAE9C,SAAO,CAAC,GAAG,SAAS,EACjB,OAAO,CAAC,aAAa,eAAe,SAAS,QAAQ,KAAK,OAAO,EACjE,KAAK,CAAC,GAAG,MAAM,eAAe,EAAE,QAAQ,IAAI,eAAe,EAAE,QAAQ,CAAC;AAC3E;AA6GA,SAAS,qBACP,UACA,WACA,UACA,YACQ;AACR,QAAM,WAAW,WACb,SAAS,aACTC,MAAK,YAAY,SAAS,iBAAiB;AAC/C,SAAOA,MAAK,UAAU,SAAS;AACjC;AAEA,eAAe,gBAAgB,OAAsD;AACnF,QAAM,YAAY,oBAAI,IAA2B;AAEjD,aAAW,QAAQ,OAAO;AACxB,QAAI,CAAC,QAAQ,UAAU,IAAI,IAAI,EAAG;AAClC,QAAI,CAACC,YAAW,IAAI,GAAG;AACrB,gBAAU,IAAI,MAAM,IAAI;AACxB;AAAA,IACF;AACA,cAAU,IAAI,MAAM,MAAMC,UAAS,MAAM,OAAO,CAAC;AAAA,EACnD;AAEA,SAAO;AACT;AAEA,eAAe,uBAAuB,WAAsD;AAC1F,aAAW,CAAC,MAAM,OAAO,KAAK,WAAW;AACvC,QAAI,YAAY,MAAM;AACpB,YAAMC,IAAG,MAAM,EAAE,OAAO,KAAK,CAAC;AAC9B;AAAA,IACF;AAEA,UAAMC,OAAM,QAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AAC9C,UAAMC,WAAU,MAAM,SAAS,OAAO;AAAA,EACxC;AACF;AAEA,eAAe,mBACb,iBACA,WACA,YACA,YACwB;AACxB,QAAM,YAAY,UAAU;AAC5B,QAAM,WAAW,UAAU,YAAY;AACvC,QAAM,gBAAgBL,MAAK,sBAAsB,SAAS;AAC1D,QAAM,mBAAmBC,YAAW,aAAa;AACjD,QAAM,sBAAsBD,MAAK,YAAY,aAAa,SAAS;AAEnE,MAAI,kBAAkB;AACpB,UAAMI,OAAM,QAAQ,mBAAmB,GAAG,EAAE,WAAW,KAAK,CAAC;AAC7D,UAAME,IAAG,eAAe,qBAAqB,EAAE,WAAW,KAAK,CAAC;AAAA,EAClE;AAEA,QAAM,gBAAqC,CAAC;AAC5C,aAAW,YAAY,iBAAiB;AACtC,UAAM,WAAW,qBAAqB,UAAU,WAAW,UAAU,UAAU;AAE/E,QAAI,CAACL,YAAW,QAAQ,GAAG;AACzB,oBAAc,KAAK,EAAE,UAAU,OAAO,UAAU,CAAC;AACjD;AAAA,IACF;AAEA,UAAMM,QAAOC,WAAU,QAAQ;AAE/B,QAAID,MAAK,eAAe,GAAG;AACzB,oBAAc,KAAK;AAAA,QACjB;AAAA,QACA,OAAO;AAAA,QACP,eAAe,MAAM,SAAS,QAAQ;AAAA,MACxC,CAAC;AACD;AAAA,IACF;AAEA,UAAM,aAAaP,MAAK,YAAY,SAAS,SAAS,IAAI,GAAG,SAAS,IAAI,SAAS,QAAQ,CAAC,EAAE;AAC9F,UAAMI,OAAM,QAAQ,UAAU,GAAG,EAAE,WAAW,KAAK,CAAC;AAEpD,QAAIG,MAAK,YAAY,GAAG;AACtB,YAAMD,IAAG,UAAU,YAAY,EAAE,WAAW,KAAK,CAAC;AAClD,oBAAc,KAAK,EAAE,UAAU,OAAO,aAAa,WAAW,CAAC;AAC/D;AAAA,IACF;AAEA,UAAMA,IAAG,UAAU,UAAU;AAC7B,kBAAc,KAAK,EAAE,UAAU,OAAO,QAAQ,WAAW,CAAC;AAAA,EAC5D;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,qBAAqB,mBAAmB,sBAAsB;AAAA,IAC9D;AAAA,IACA;AAAA,EACF;AACF;AAEA,eAAe,qBAAqB,UAAwC;AAC1E,MAAIL,YAAW,SAAS,aAAa,GAAG;AACtC,UAAME,IAAG,SAAS,eAAe,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,EACnE;AAEA,MAAI,SAAS,oBAAoB,SAAS,uBAAuBF,YAAW,SAAS,mBAAmB,GAAG;AACzG,UAAMG,OAAM,QAAQ,SAAS,aAAa,GAAG,EAAE,WAAW,KAAK,CAAC;AAChE,UAAME,IAAG,SAAS,qBAAqB,SAAS,eAAe,EAAE,WAAW,KAAK,CAAC;AAAA,EACpF;AAEA,aAAW,gBAAgB,SAAS,eAAe;AACjD,UAAMH,IAAG,aAAa,UAAU,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAEhE,QAAI,aAAa,UAAU,UAAW;AAEtC,UAAMC,OAAM,QAAQ,aAAa,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;AAE/D,QAAI,aAAa,UAAU,aAAa,aAAa,eAAe;AAClE,YAAM,WAAW,QAAQ,aAAa,UAAU,aAAa;AAC7D,YAAMK,SAAQ,aAAa,eAAe,aAAa,UAAU,QAAQ;AACzE;AAAA,IACF;AAEA,SAAK,aAAa,UAAU,eAAe,aAAa,UAAU,WAAW,aAAa,YAAY;AACpG,UAAI,aAAa,UAAU,aAAa;AACtC,cAAMH,IAAG,aAAa,YAAY,aAAa,UAAU,EAAE,WAAW,KAAK,CAAC;AAAA,MAC9E,OAAO;AACL,cAAMA,IAAG,aAAa,YAAY,aAAa,QAAQ;AAAA,MACzD;AAAA,IACF;AAAA,EACF;AACF;AA4BA,eAAsB,yBACpB,SAC6B;AAC7B,QAAM,aAAa,QAAQ,cAAc,QAAQ,IAAI;AACrD,QAAM,kBAAkB,QAAQ,mBAAmB;AACnD,QAAM,SAAS,QAAQ,OAAO,CAAC;AAC/B,QAAM,WAAW,QAAQ,UAAU,CAAC;AACpC,QAAM,gBAAgB,QAAQ,aAAa,sBAAsB;AACjE,QAAM,YAAY,iCAAiC,eAAe,eAAe;AAEjF,QAAM,cAAc,UAAU,QAAQ,CAAC,aAAa;AAClD,UAAM,QAAkB,CAAC;AACzB,eAAW,aAAa,QAAQ;AAC9B,YAAM,OAAO,kBAAkB,UAAU,UAAU,SAAS,WAAW,UAAU;AACjF,UAAI,KAAM,OAAM,KAAK,IAAI;AAAA,IAC3B;AACA,WAAO;AAAA,EACT,CAAC;AAED,QAAM,kBAAkB,MAAM,gBAAgB,WAAW;AACzD,QAAM,aAAaN;AAAA,IACjB,OAAO;AAAA,IACP,sBAAsB,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC;AAAA,EAC5E;AAEA,QAAM,iBAAiB,MAAM,QAAQ;AAAA,IACnC,SAAS,IAAI,CAAC,cAAc,mBAAmB,WAAW,WAAW,YAAY,UAAU,CAAC;AAAA,EAC9F;AAEA,QAAM,gBAAuC,CAAC;AAC9C,QAAM,iBAA2B,CAAC;AAClC,MAAI,aAAa;AACjB,MAAI,gBAAgB;AACpB,MAAI,oBAAoB;AAExB,MAAI;AACF,eAAW,aAAa,QAAQ;AAC9B,YAAM,QAAQ,UAAU,SAAS;AACjC,iBAAW,YAAY,WAAW;AAChC,cAAM,SAAS,MAAM;AAAA,UACnB;AAAA,UACA,UAAU;AAAA,UACV,UAAU;AAAA,UACV;AAAA,UACA;AAAA,QACF;AAEA,YAAI,CAAC,OAAO,SAAS;AACnB,gBAAM,IAAI,MAAM,OAAO,SAAS,0BAA0B,SAAS,EAAE,EAAE;AAAA,QACzE;AACA,sBAAc;AAAA,MAChB;AAAA,IACF;AAEA,eAAW,aAAa,UAAU;AAChC,YAAM,WAAW,UAAU,YAAY;AACvC,YAAM,SAAS,MAAM;AAAA,QACnB,UAAU;AAAA,QACV,UAAU;AAAA,QACV;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAEA,YAAM,kBAAkB,UAAU,OAAO,CAAC,aAAa,OAAO,aAAa,SAAS,SAAS,EAAE,CAAC;AAChG,oBAAc,KAAK;AAAA,QACjB,WAAW,UAAU;AAAA,QACrB;AAAA,QACA;AAAA,MACF,CAAC;AAED,UAAI,OAAO,OAAO,SAAS,GAAG;AAC5B,cAAM,IAAI,MAAM,OAAO,OAAO,KAAK,IAAI,CAAC;AAAA,MAC1C;AAEA,uBAAiB;AAAA,IACnB;AAEA,UAAMG,IAAG,YAAY,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAErD,WAAO;AAAA,MACL,SAAS;AAAA,MACT,aAAa,UAAU,IAAI,CAAC,aAAa,SAAS,EAAE;AAAA,MACpD;AAAA,MACA;AAAA,MACA,mBAAmB;AAAA,MACnB,gBAAgB,CAAC;AAAA,IACnB;AAAA,EACF,SAAS,OAAO;AACd,wBAAoB;AAEpB,eAAW,WAAW,CAAC,GAAG,aAAa,EAAE,QAAQ,GAAG;AAClD,UAAI;AACF,cAAM,YAAY,QAAQ,WAAW,QAAQ,iBAAiB,QAAQ,UAAU,UAAU;AAAA,MAC5F,SAAS,KAAK;AACZ,uBAAe,KAAK,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,MACtE;AAAA,IACF;AAEA,QAAI;AACF,YAAM,uBAAuB,eAAe;AAAA,IAC9C,SAAS,KAAK;AACZ,qBAAe,KAAK,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,IACtE;AAEA,eAAW,YAAY,gBAAgB;AACrC,UAAI;AACF,cAAM,qBAAqB,QAAQ;AAAA,MACrC,SAAS,KAAK;AACZ,uBAAe,KAAK,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,MACtE;AAAA,IACF;AAEA,UAAMA,IAAG,YAAY,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAErD,WAAO;AAAA,MACL,SAAS;AAAA,MACT,aAAa,UAAU,IAAI,CAAC,aAAa,SAAS,EAAE;AAAA,MACpD;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,IAC9D;AAAA,EACF;AACF;AAyEA,SAAS,gBAAgB,OAAwB;AAC/C,MAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,WAAO,IAAI,MAAM,IAAI,eAAe,EAAE,KAAK,GAAG,CAAC;AAAA,EACjD;AAEA,MAAI,SAAS,OAAO,UAAU,UAAU;AACtC,UAAM,SAAS;AACf,UAAM,OAAO,OAAO,KAAK,MAAM,EAAE,KAAK;AACtC,WAAO,IAAI,KAAK,IAAI,CAAC,QAAQ,GAAG,KAAK,UAAU,GAAG,CAAC,IAAI,gBAAgB,OAAO,GAAG,CAAC,CAAC,EAAE,EAAE,KAAK,GAAG,CAAC;AAAA,EAClG;AAEA,SAAO,KAAK,UAAU,KAAK;AAC7B;AA0BA,eAAsB,yBACpB,WACA,YACA,aAAa,QAAQ,IAAI,GACD;AACxB,QAAM,YAA2B,CAAC;AAElC,aAAW,YAAY,WAAW;AAChC,eAAW,aAAa,YAAY;AAClC,YAAM,QAAQ,UAAU,SAAS;AAEjC,UAAI,UAAU,OAAO,QAAQ,CAAC,SAAS,oBAAoB,SAAS,UAAU,OAAO,IAAI,GAAG;AAC1F,kBAAU,KAAK;AAAA,UACb,YAAY,SAAS;AAAA,UACrB,YAAY,UAAU;AAAA,UACtB;AAAA,UACA,MAAM;AAAA,UACN,SAAS,GAAG,SAAS,EAAE,+BAA+B,UAAU,OAAO,IAAI;AAAA,QAC7E,CAAC;AAAA,MACH;AAEA,UAAI,UAAU,OAAO,WAAW,CAAC,SAAS,iBAAiB;AACzD,kBAAU,KAAK;AAAA,UACb,YAAY,SAAS;AAAA,UACrB,YAAY,UAAU;AAAA,UACtB;AAAA,UACA,MAAM;AAAA,UACN,SAAS,GAAG,SAAS,EAAE;AAAA,QACzB,CAAC;AAAA,MACH;AAEA,YAAM,kBAAkB,MAAM,eAAe,UAAU,OAAO,UAAU;AACxE,YAAM,UAAU,gBAAgB,KAAK,CAAC,UAAU,MAAM,SAAS,UAAU,UAAU;AACnF,UAAI,CAAC,QAAS;AAEd,YAAM,YAAY,aAAa,SAAS,EAAE;AAC1C,YAAM,UAAU,YACZ,UAAU,UAAU,YAAY,UAAU,MAAM,IAChD,UAAU;AAEd,UAAI,gBAAgB,QAAQ,MAAM,MAAM,gBAAgB,OAAO,GAAG;AAChE,kBAAU,KAAK;AAAA,UACb,YAAY,SAAS;AAAA,UACrB,YAAY,UAAU;AAAA,UACtB;AAAA,UACA,MAAM;AAAA,UACN,SAAS,GAAG,SAAS,EAAE,qCAAqC,UAAU,UAAU;AAAA,QAClF,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAyBA,eAAsB,0BACpB,WACA,YACA,SAAyB,QACzB,aAAa,QAAQ,IAAI,GACI;AAC7B,QAAM,YAAY,MAAM,yBAAyB,WAAW,YAAY,UAAU;AAClF,QAAM,cAAc,CAAC,YAAoB,YAAoB,UAAiB,GAAG,UAAU,KAAK,UAAU,KAAK,KAAK;AACpH,QAAM,cAAc,oBAAI,IAAyB;AACjD,aAAW,YAAY,WAAW;AAChC,gBAAY,IAAI,YAAY,SAAS,YAAY,SAAS,YAAY,SAAS,KAAK,GAAG,QAAQ;AAAA,EACjG;AAEA,MAAI,WAAW,UAAU,UAAU,SAAS,GAAG;AAC7C,WAAO,EAAE,WAAW,SAAS,CAAC,GAAG,SAAS,CAAC,EAAE;AAAA,EAC/C;AAEA,QAAM,UAA2B,CAAC;AAClC,QAAM,UAAyC,CAAC;AAEhD,aAAW,YAAY,WAAW;AAChC,eAAW,aAAa,YAAY;AAClC,YAAM,QAAQ,UAAU,SAAS;AACjC,YAAM,MAAM,YAAY,SAAS,IAAI,UAAU,YAAY,KAAK;AAChE,YAAM,WAAW,YAAY,IAAI,GAAG;AAEpC,UAAI,WAAW,UAAU,UAAU;AACjC,gBAAQ,KAAK;AAAA,UACX,YAAY,SAAS;AAAA,UACrB,YAAY,UAAU;AAAA,UACtB;AAAA,UACA,QAAQ,SAAS;AAAA,QACnB,CAAC;AACD;AAAA,MACF;AAEA,YAAM,SAAS,MAAM;AAAA,QACnB;AAAA,QACA,UAAU;AAAA,QACV,UAAU;AAAA,QACV;AAAA,QACA;AAAA,MACF;AACA,cAAQ,KAAK,MAAM;AAAA,IACrB;AAAA,EACF;AAEA,SAAO,EAAE,WAAW,SAAS,QAAQ;AACvC;AAoDA,eAAsB,kCACpB,WACA,SACA,QAAe,WACf,aAAa,QAAQ,IAAI,GACU;AACnC,QAAM,UAAU,MAAM,UAAU,WAAW,YAAY,OAAO,OAAO;AACrE,QAAM,gBAAgB,oBAAoB,SAAS;AAEnD,QAAM,UAAoC;AAAA,IACxC;AAAA,IACA,cAAc,QAAQ;AAAA,IACtB,SAAS,CAAC;AAAA,EACZ;AAEA,aAAW,CAAC,UAAU,MAAM,KAAK,QAAQ,QAAQ,GAAG;AAClD,UAAM,mBAAmB,UAAU,OAAO,CAAC,aAAa;AACtD,YAAM,eAAe,UAAU,WAC3BH,MAAK,SAAS,YAAY,SAAS,YAAY,IAC/CA,MAAK,YAAY,SAAS,YAAY;AAC1C,aAAO,iBAAiB;AAAA,IAC1B,CAAC;AAED,UAAM,WAAW,cAAc,IAAI,SAAS,QAAQ,CAAC,KAAK,CAAC;AAC3D,UAAM,WAAW,iBAAiB,SAAS,IAAI,mBAAmB;AAElE,YAAQ,QAAQ,KAAK;AAAA,MACnB,MAAM;AAAA,MACN;AAAA,MACA,WAAW,SAAS,IAAI,CAAC,aAAa,SAAS,EAAE;AAAA,MACjD,eAAe,MAAM,KAAK,IAAI,IAAI,SAAS,IAAI,CAAC,aAAa,SAAS,YAAY,CAAC,CAAC;AAAA,IACtF,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AA2EA,eAAsB,kCACpB,UACA,SACmC;AACnC,QAAM,aAAa,QAAQ,cAAc,QAAQ,IAAI;AACrD,QAAM,YAAY,QAAQ,aAAa,CAAC;AACxC,QAAM,aAAa,QAAQ,cAAc,CAAC;AAE1C,QAAM,gBAAiC,CAAC;AACxC,aAAW,aAAa,WAAW;AACjC,kBAAc,KAAK,MAAM;AAAA,MACvB;AAAA,MACA,UAAU;AAAA,MACV,UAAU;AAAA,MACV;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AAEA,QAAM,iBAAkC,CAAC;AACzC,aAAW,aAAa,YAAY;AAClC,mBAAe,KAAK,MAAM;AAAA,MACxB;AAAA,MACA,UAAU;AAAA,MACV,UAAU;AAAA,MACV;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AAEA,QAAM,qBAA+D,CAAC;AACtE,QAAM,qBAAqB,QAAQ;AACnC,MAAI,OAAO,uBAAuB,UAAU;AAC1C,uBAAmB,SAAS,MAAM,UAAU,CAAC,QAAQ,GAAG,YAAY,UAAU,kBAAkB;AAChG,uBAAmB,UAAU,MAAM,UAAU,CAAC,QAAQ,GAAG,YAAY,WAAW,kBAAkB;AAAA,EACpG,WAAW,oBAAoB;AAC7B,QAAI,mBAAmB,QAAQ;AAC7B,yBAAmB,SAAS,MAAM,UAAU,CAAC,QAAQ,GAAG,YAAY,UAAU,mBAAmB,MAAM;AAAA,IACzG;AACA,QAAI,mBAAmB,SAAS;AAC9B,yBAAmB,UAAU,MAAM,UAAU,CAAC,QAAQ,GAAG,YAAY,WAAW,mBAAmB,OAAO;AAAA,IAC5G;AAAA,EACF;AAEA,SAAO;AAAA,IACL,YAAY,SAAS;AAAA,IACrB,aAAa;AAAA,MACX,QAAQ,kBAAkB,UAAU,UAAU,UAAU;AAAA,MACxD,SAAS,kBAAkB,UAAU,WAAW,UAAU;AAAA,IAC5D;AAAA,IACA,KAAK;AAAA,MACH,QAAQ;AAAA,MACR,SAAS;AAAA,IACX;AAAA,IACA,cAAc;AAAA,EAChB;AACF;;;AEl5BA,SAAS,gBAAAU,qBAAoB;AAC7B,SAAS,cAAAC,mBAAkB;AAC3B,SAAS,eAAe;AACxB,SAAS,YAAY,WAAAC,gBAAe;AAuB7B,IAAM,oBAAiD;AAAA,EAC5D,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,KAAK;AACP;AAWO,IAAM,uBAAuB;AAW7B,IAAM,uBAAuB;AAsF7B,SAAS,qBAAqB,OAA6B;AAChE,MAAI,CAAC,SAAS,MAAM,KAAK,MAAM,GAAI,QAAO;AAC1C,QAAM,aAAa,MAAM,KAAK,EAAE,YAAY;AAC5C,MAAI,eAAe,YAAY,eAAe,UAAU,eAAe,OAAO;AAC5E,WAAO;AAAA,EACT;AACA,QAAM,IAAI,MAAM,oBAAqB,KAAK,mCAAoC;AAChF;AAoBO,SAAS,sBAAsB,SAA8B;AAClE,SAAO,kBAAkB,OAAO;AAClC;AAoBO,SAAS,6BAA6B,YAAwC;AACnF,MAAI,eAAe,kBAAkB,OAAQ,QAAO;AACpD,MAAI,eAAe,kBAAkB,KAAM,QAAO;AAClD,MAAI,eAAe,kBAAkB,IAAK,QAAO;AACjD,SAAO;AACT;AAEA,SAAS,aAAa,SAAiB,eAAyB,CAAC,GAAwC;AACvG,MAAI,aAAa,SAAS,GAAG;AAC3B,WAAO,EAAE,SAAS,MAAM,aAAa;AAAA,EACvC;AACA,QAAM,QAAQ,QAAQ,KAAK,EAAE,MAAM,KAAK;AACxC,QAAM,SAAS,MAAM,CAAC,KAAK;AAC3B,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI,MAAM,sCAAsC;AAAA,EACxD;AACA,SAAO;AAAA,IACL,SAAS;AAAA,IACT,MAAM,MAAM,MAAM,CAAC;AAAA,EACrB;AACF;AAEA,SAAS,aACP,KACA,SACA,SACoC;AACpC,QAAM,SAAS,EAAE,GAAI,OAAO,CAAC,EAAG;AAChC,MAAI,YAAY,SAAS,CAAC,OAAO,UAAU;AACzC,WAAO,WAAW,WAAW;AAAA,EAC/B;AACA,SAAO,OAAO,KAAK,MAAM,EAAE,SAAS,IAAI,SAAS;AACnD;AAEA,SAAS,mBAAmB,SAAsB,SAA0B;AAC1E,QAAM,MAAM,SAAS,KAAK,MAAM,YAAY,WAAW,WAAW;AAClE,SAAO,GAAG,oBAAoB,IAAI,GAAG;AACvC;AAwBO,SAAS,iBAAiB,SAA0D;AACzF,QAAM,UAAU,QAAQ;AACxB,QAAM,aAAa,sBAAsB,OAAO;AAEhD,MAAI,YAAY,OAAO;AACrB,QAAI,CAAC,QAAQ,WAAW,QAAQ,QAAQ,KAAK,MAAM,IAAI;AACrD,YAAM,IAAI,MAAM,iCAAiC;AAAA,IACnD;AAEA,UAAM,SAAS,aAAa,QAAQ,SAAS,QAAQ,QAAQ,CAAC,CAAC;AAC/D,UAAM,MAAM,aAAa,QAAQ,KAAK,SAAS,QAAQ,OAAO;AAC9D,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,QAAQ;AAAA,QACN,SAAS,OAAO;AAAA,QAChB,MAAM,OAAO;AAAA,QACb,GAAI,MAAM,EAAE,IAAI,IAAI,CAAC;AAAA,MACvB;AAAA,IACF;AAAA,EACF;AAEA,QAAM,cAAc,mBAAmB,SAAS,QAAQ,OAAO;AAC/D,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,MACN,SAAS;AAAA,MACT,MAAM,CAAC,MAAM,aAAa,KAAK;AAAA,IACjC;AAAA,EACF;AACF;AAEA,SAAS,WAAW,WAA2B;AAC7C,MAAI,cAAc,IAAK,QAAO,QAAQ;AACtC,MAAI,UAAU,WAAW,IAAI,GAAG;AAC9B,WAAOA,SAAQ,QAAQ,GAAG,UAAU,MAAM,CAAC,CAAC;AAAA,EAC9C;AACA,SAAO;AACT;AAuBO,SAAS,yBAAyB,SAAsC;AAC7E,QAAM,mBAAmB,QAAQ,SAAS,GAAG,KAAK,QAAQ,SAAS,IAAI;AACvE,MAAI,oBAAoB,QAAQ,WAAW,GAAG,GAAG;AAC/C,UAAM,WAAW,WAAW,OAAO;AACnC,UAAM,YAAY,WAAW,QAAQ,IAAI,WAAWA,SAAQ,QAAQ,IAAI,GAAG,QAAQ;AACnF,QAAID,YAAW,SAAS,GAAG;AACzB,aAAO,EAAE,WAAW,MAAM,QAAQ,QAAQ,QAAQ,UAAU;AAAA,IAC9D;AACA,WAAO,EAAE,WAAW,OAAO,QAAQ,QAAQ,QAAQ,UAAU;AAAA,EAC/D;AAEA,MAAI;AACF,UAAM,SAAS,QAAQ,aAAa,UAAU,UAAU;AACxD,IAAAD,cAAa,QAAQ,CAAC,OAAO,GAAG,EAAE,OAAO,OAAO,CAAC;AACjD,WAAO,EAAE,WAAW,MAAM,QAAQ,UAAU,QAAQ,QAAQ;AAAA,EAC9D,QAAQ;AACN,WAAO,EAAE,WAAW,OAAO,QAAQ,UAAU,QAAQ,QAAQ;AAAA,EAC/D;AACF;AAqBO,SAAS,oBAAoB,QAA0C;AAC5E,QAAM,MAA8B,CAAC;AACrC,aAAW,SAAS,QAAQ;AAC1B,UAAM,MAAM,MAAM,QAAQ,GAAG;AAC7B,QAAI,OAAO,GAAG;AACZ,YAAM,IAAI,MAAM,wBAAyB,KAAK,mBAAoB;AAAA,IACpE;AACA,UAAM,MAAM,MAAM,MAAM,GAAG,GAAG,EAAE,KAAK;AACrC,UAAM,MAAM,MAAM,MAAM,MAAM,CAAC,EAAE,KAAK;AACtC,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,wBAAyB,KAAK,yBAA0B;AAAA,IAC1E;AACA,QAAI,GAAG,IAAI;AAAA,EACb;AACA,SAAO;AACT;AAqBO,SAAS,kBAAkB,aAA0C;AAC1E,MAAI,CAAC,YAAa,QAAO;AACzB,QAAM,UAAU,YAAY,YAAY,GAAG;AAC3C,MAAI,WAAW,EAAG,QAAO;AACzB,SAAO,YAAY,MAAM,UAAU,CAAC;AACtC;AAqBO,SAAS,aAAa,QAAyB;AACpD,SAAO,OAAO,KAAK,EAAE,YAAY,MAAM;AACzC;;;AC3ZA,SAAS,MAAM,YAAAG,WAAU,aAAAC,YAAW,SAAAC,QAAO,MAAAC,KAAI,QAAQ,YAAY;AACnE,SAAS,cAAAC,mBAAkB;AAI3B,IAAM,kBAAkB,GAAG,cAAc;AACzC,IAAM,gBAAgB;AAEtB,SAAS,MAAM,IAA2B;AACxC,SAAO,IAAI,QAAQ,CAACC,aAAY,WAAWA,UAAS,EAAE,CAAC;AACzD;AAEA,eAAe,kBAAoC;AACjD,MAAI;AACF,UAAM,OAAO,MAAM,KAAK,eAAe;AACvC,QAAI,KAAK,IAAI,IAAI,KAAK,UAAU,eAAe;AAC7C,YAAMC,IAAG,iBAAiB,EAAE,OAAO,KAAK,CAAC;AACzC,aAAO;AAAA,IACT;AAAA,EACF,QAAQ;AAAA,EAER;AACA,SAAO;AACT;AAEA,eAAe,iBAAiB,UAAU,IAAI,UAAU,IAAmB;AACzE,QAAMC,OAAM,aAAa,EAAE,WAAW,KAAK,CAAC;AAE5C,WAAS,UAAU,GAAG,UAAU,SAAS,WAAW,GAAG;AACrD,QAAI;AACF,YAAM,SAAS,MAAM,KAAK,iBAAiB,IAAI;AAC/C,YAAM,OAAO,MAAM;AACnB;AAAA,IACF,SAAS,OAAO;AACd,UAAI,EAAE,iBAAiB,UAAU,EAAE,UAAU,UAAW,MAAgC,SAAS,UAAU;AACzG,cAAM;AAAA,MACR;AAEA,UAAI,YAAY,GAAG;AACjB,cAAM,UAAU,MAAM,gBAAgB;AACtC,YAAI,QAAS;AAAA,MACf;AACA,YAAM,MAAM,OAAO;AAAA,IACrB;AAAA,EACF;AAEA,QAAM,IAAI,MAAM,uCAAuC;AACzD;AAEA,eAAe,mBAAkC;AAC/C,QAAMD,IAAG,iBAAiB,EAAE,OAAO,KAAK,CAAC;AAC3C;AAEA,eAAe,oBAAoB,MAAoC;AACrE,QAAM,UAAU,GAAG,cAAc,QAAQ,QAAQ,GAAG,IAAI,KAAK,IAAI,CAAC;AAClE,QAAME,WAAU,SAAS,KAAK,UAAU,MAAM,MAAM,CAAC,IAAI,MAAM,OAAO;AACtE,QAAM,OAAO,SAAS,cAAc;AACtC;AAmBA,eAAsB,eAAuC;AAC3D,MAAI;AACF,QAAI,CAACC,YAAW,cAAc,GAAG;AAC/B,aAAO,EAAE,SAAS,GAAG,QAAQ,CAAC,GAAG,YAAY,CAAC,EAAE;AAAA,IAClD;AACA,UAAM,UAAU,MAAMC,UAAS,gBAAgB,OAAO;AACtD,WAAO,KAAK,MAAM,OAAO;AAAA,EAC3B,QAAQ;AACN,WAAO,EAAE,SAAS,GAAG,QAAQ,CAAC,GAAG,YAAY,CAAC,EAAE;AAAA,EAClD;AACF;AAiDA,eAAsB,eACpB,SACwB;AACxB,QAAM,iBAAiB;AACvB,MAAI;AACF,UAAM,OAAO,MAAM,aAAa;AAChC,UAAM,QAAQ,IAAI;AAClB,UAAM,oBAAoB,IAAI;AAC9B,WAAO;AAAA,EACT,UAAE;AACA,UAAM,iBAAiB;AAAA,EACzB;AACF;;;AC/FA,eAAsB,iBACpB,YACA,QACA,YACA,QACA,UACA,SACe;AACf,QAAM,eAAe,CAAC,SAAS;AAC7B,UAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AACnC,UAAM,WAAW,KAAK,WAAW,UAAU;AAE3C,SAAK,WAAW,UAAU,IAAI;AAAA,MAC5B,MAAM;AAAA,MACN,YAAY;AAAA,MACZ;AAAA,MACA;AAAA,MACA,SAAS,WAAW,UAAU;AAAA,MAC9B,aAAa,UAAU,eAAe;AAAA,MACtC,WAAW;AAAA,MACX,QAAQ,CAAC,GAAG,oBAAI,IAAI,CAAC,GAAI,UAAU,UAAU,CAAC,GAAI,GAAG,MAAM,CAAC,CAAC;AAAA,MAC7D,eAAe;AAAA,MACf;AAAA,IACF;AAAA,EACF,CAAC;AACH;AAsBA,eAAsB,kBAAkB,YAAsC;AAC5E,MAAI,UAAU;AACd,QAAM,eAAe,CAAC,SAAS;AAC7B,QAAI,EAAE,cAAc,KAAK,YAAa;AACtC,WAAO,KAAK,WAAW,UAAU;AACjC,cAAU;AAAA,EACZ,CAAC;AACD,SAAO;AACT;AAsBA,eAAsB,uBAA2D;AAC/E,QAAM,OAAO,MAAM,aAAa;AAChC,SAAO,KAAK;AACd;AAqBA,eAAsB,uBAAuB,QAAiC;AAC5E,QAAM,eAAe,CAAC,SAAS;AAC7B,SAAK,qBAAqB;AAAA,EAC5B,CAAC;AACH;AAoBA,eAAsB,wBAAuD;AAC3E,QAAM,OAAO,MAAM,aAAa;AAChC,SAAO,KAAK;AACd;;;AC9HO,SAAS,kBACd,QACA,SACkB;AAClB,QAAM,UAAU,OAAO,OAAO,YAAY,WAAW,OAAO,UAAU;AACtE,QAAM,OAAO,MAAM,QAAQ,OAAO,IAAI,IAClC,OAAO,KAAK,OAAO,CAAC,MAAmB,OAAO,MAAM,QAAQ,IAC5D,CAAC;AAGL,QAAM,aAAa,KAAK;AAAA,IACtB,CAAC,MAAM,EAAE,SAAS,oBAAoB;AAAA,EACxC;AAEA,MAAI,YAAY;AACd,UAAM,UAAU,kBAAkB,UAAU;AAC5C,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,YAAY;AAAA,MACZ;AAAA,IACF;AAAA,EACF;AAGA,MAAI,YAAY,SAAS,QAAQ,SAAS,GAAG,KAAK,QAAQ,SAAS,IAAI,GAAG;AACxE,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,YAAY;AAAA,MACZ,SAAS;AAAA,IACX;AAAA,EACF;AAGA,QAAM,OAAO,KAAK,SAAS,IAAI,GAAG,OAAO,IAAI,KAAK,KAAK,GAAG,CAAC,KAAK;AAChE,SAAO;AAAA,IACL,QAAQ,QAAQ;AAAA,IAChB,YAAY;AAAA,IACZ,SAAS;AAAA,EACX;AACF;AAyEA,eAAsB,kBACpB,UAA4B,CAAC,GACH;AAC1B,QAAM,SAA0B;AAAA,IAC9B,YAAY,CAAC;AAAA,IACb,QAAQ,CAAC;AAAA,IACT,gBAAgB;AAAA,IAChB,QAAQ,CAAC;AAAA,EACX;AAEA,QAAM,cAAc,MAAM,qBAAqB;AAC/C,QAAM,YAAY,sBAAsB;AAGxC,QAAM,kBAAkB,QAAQ,aAAa,SACzC,UAAU,OAAO,CAAC,MAAM,QAAQ,YAAa,SAAS,EAAE,EAAE,CAAC,IAC3D;AAGJ,QAAM,SAAsC,CAAC;AAC7C,MAAI,QAAQ,UAAU,CAAC,QAAQ,SAAS;AACtC,WAAO,KAAK,QAAQ;AAAA,EACtB,WAAW,QAAQ,WAAW,CAAC,QAAQ,QAAQ;AAC7C,WAAO,KAAK,SAAS;AAAA,EACvB,OAAO;AACL,WAAO,KAAK,WAAW,QAAQ;AAAA,EACjC;AAWA,QAAM,SAAS,oBAAI,IAAwB;AAC3C,QAAM,sBAAsB,oBAAI,IAAY;AAE5C,aAAW,SAAS,QAAQ;AAC1B,eAAW,YAAY,iBAAiB;AACtC,UAAI;AACJ,UAAI;AACF,kBAAU,MAAM,eAAe,UAAU,KAAK;AAAA,MAChD,QAAQ;AACN,eAAO,OAAO,KAAK;AAAA,UACjB,SAAS,6BAA6B,SAAS,EAAE,KAAK,KAAK;AAAA,QAC7D,CAAC;AACD;AAAA,MACF;AAEA,iBAAW,SAAS,SAAS;AAC3B,cAAM,UAAU,6BAA6B,MAAM,IAAI;AACvD,YAAI,CAAC,QAAS;AAEd,4BAAoB,IAAI,MAAM,IAAI;AAElC,cAAM,WAAW,UAAU;AAC3B,cAAM,WAAW,GAAG,MAAM,IAAI,IAAI,WAAW,WAAW,SAAS;AAEjE,YAAI,YAAY,MAAM,IAAI,MAAM,QAAW;AAEzC,gBAAMC,YAAW,OAAO,IAAI,QAAQ;AACpC,cAAI,CAACA,WAAU;AACb,mBAAO;AAAA,UACT;AACA;AAAA,QACF;AAEA,cAAM,WAAW,OAAO,IAAI,QAAQ;AACpC,YAAI,UAAU;AACZ,cAAI,CAAC,SAAS,OAAO,SAAS,SAAS,EAAE,GAAG;AAC1C,qBAAS,OAAO,KAAK,SAAS,EAAE;AAAA,UAClC;AAAA,QACF,OAAO;AACL,iBAAO,IAAI,UAAU;AAAA,YACnB,YAAY,MAAM;AAAA,YAClB;AAAA,YACA;AAAA,YACA,QAAQ,CAAC,SAAS,EAAE;AAAA,YACpB,QAAQ,MAAM;AAAA,UAChB,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,aAAW,SAAS,OAAO,OAAO,GAAG;AACnC,UAAM,WAAW,kBAAkB,MAAM,QAAQ,MAAM,OAAO;AAE9D,QAAI,CAAC,QAAQ,QAAQ;AACnB,UAAI;AACF,cAAM;AAAA,UACJ,MAAM;AAAA,UACN,SAAS;AAAA,UACT,SAAS;AAAA,UACT,MAAM;AAAA,UACN,MAAM,UAAU;AAAA,UAChB,SAAS;AAAA,QACX;AAAA,MACF,SAAS,KAAK;AACZ,eAAO,OAAO,KAAK;AAAA,UACjB,SAAS,sBAAsB,MAAM,UAAU,KAAK,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,QACtG,CAAC;AACD;AAAA,MACF;AAAA,IACF;AAEA,WAAO,WAAW,KAAK;AAAA,MACrB,YAAY,MAAM;AAAA,MAClB,SAAS,MAAM;AAAA,MACf,OAAO,MAAM;AAAA,MACb,QAAQ,MAAM;AAAA,MACd,QAAQ,SAAS;AAAA,MACjB,YAAY,SAAS;AAAA,MACrB,SAAS,SAAS;AAAA,IACpB,CAAC;AAAA,EACH;AAGA,MAAI,QAAQ,OAAO;AACjB,eAAW,CAAC,UAAU,KAAK,OAAO,QAAQ,WAAW,GAAG;AACtD,YAAM,UAAU,6BAA6B,UAAU;AACvD,UAAI,CAAC,QAAS;AAEd,UAAI,CAAC,oBAAoB,IAAI,UAAU,GAAG;AACxC,YAAI,CAAC,QAAQ,QAAQ;AACnB,cAAI;AACF,kBAAM,kBAAkB,UAAU;AAAA,UACpC,SAAS,KAAK;AACZ,mBAAO,OAAO,KAAK;AAAA,cACjB,SAAS,mBAAmB,UAAU,KAAK,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,YAC7F,CAAC;AACD;AAAA,UACF;AAAA,QACF;AACA,eAAO,OAAO,KAAK,UAAU;AAAA,MAC/B;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;;;ACpTA,IAAM,mBAAmB;AACzB,IAAM,aAAa;AACnB,IAAM,aAAa;AACnB,IAAM,WAAW;AACjB,IAAM,aAAa;AACnB,IAAM,cAAc;AACpB,IAAM,gBAAgB;AAGtB,SAAS,UAAU,QAAgB,MAA0B;AAC3D,MAAI,SAAS,WAAW;AACtB,UAAM,QAAQ,OAAO,MAAM,aAAa;AACxC,WAAO,QAAQ,CAAC,KAAK;AAAA,EACvB;AAEA,MAAI,SAAS,UAAU;AACrB,QAAI;AACF,YAAM,MAAM,IAAI,IAAI,MAAM;AAE1B,YAAM,QAAQ,IAAI,SAAS,MAAM,GAAG;AACpC,UAAI,MAAM,UAAU,GAAG;AACrB,cAAM,WAAW,MAAM,CAAC,KAAK;AAC7B,cAAM,cAAc,MAAM,MAAM,SAAS,CAAC,KAAK;AAC/C,cAAM,QAAQ,MAAM,WAAW,IAAI,cAAc;AACjD,YAAI,UAAU,SAAS,UAAU,SAAS,UAAU,OAAO;AACzD,iBAAO;AAAA,QACT;AAEA,eAAO;AAAA,MACT;AACA,aAAO,MAAM,CAAC,KAAK;AAAA,IACrB,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAEA,MAAI,SAAS,WAAW;AAEtB,QAAI,OAAO,OAAO,QAAQ,aAAa,EAAE;AACzC,WAAO,KAAK,QAAQ,gBAAgB,EAAE;AACtC,WAAO,KAAK,QAAQ,YAAY,EAAE;AAClC,WAAO,KAAK,QAAQ,SAAS,EAAE;AAC/B,WAAO,KAAK,QAAQ,YAAY,EAAE;AAClC,WAAO;AAAA,EACT;AAEA,MAAI,SAAS,YAAY,SAAS,UAAU;AAE1C,UAAM,QAAQ,OAAO,MAAM,uBAAuB;AAClD,WAAO,QAAQ,CAAC,KAAK;AAAA,EACvB;AAEA,MAAI,SAAS,SAAS;AAEpB,UAAM,aAAa,OAAO,QAAQ,OAAO,GAAG,EAAE,QAAQ,QAAQ,EAAE;AAChE,UAAM,cAAc,WAAW,MAAM,GAAG,EAAE,IAAI;AAC9C,WAAO,eAAe;AAAA,EACxB;AAEA,MAAI,SAAS,WAAW;AAEtB,UAAM,QAAQ,OAAO,MAAM,KAAK;AAChC,UAAM,UAAU,MAAM,KAAK,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,KAAK,MAAM,SAAS,MAAM,UAAU,MAAM,YAAY,MAAM,SAAS;AACxH,WAAO,WAAW,MAAM,CAAC,KAAK;AAAA,EAChC;AAEA,SAAO;AACT;AA2BO,SAAS,YAAY,OAA6B;AAEvD,QAAM,aAAa,MAAM,MAAM,UAAU;AACzC,MAAI,YAAY;AACd,UAAM,QAAQ,WAAW,CAAC;AAC1B,UAAM,OAAO,WAAW,CAAC;AACzB,UAAM,OAAO,WAAW,CAAC;AACzB,QAAI,CAAC,SAAS,CAAC,MAAM;AACnB,aAAO,EAAE,MAAM,WAAW,OAAO,OAAO,cAAc,UAAU,OAAO,SAAS,EAAE;AAAA,IACpF;AAEA,UAAM,eAAe,OAAO,KAAK,MAAM,GAAG,EAAE,IAAI,KAAK,OAAO;AAC5D,WAAO;AAAA,MACL,MAAM;AAAA,MACN,OAAO;AAAA,MACP;AAAA,MACA;AAAA,MACA;AAAA,MACA,KAAK,WAAW,CAAC;AAAA,MACjB;AAAA,IACF;AAAA,EACF;AAGA,QAAM,aAAa,MAAM,MAAM,UAAU;AACzC,MAAI,YAAY;AACd,UAAM,QAAQ,WAAW,CAAC;AAC1B,UAAM,OAAO,WAAW,CAAC;AACzB,UAAM,OAAO,WAAW,CAAC;AACzB,QAAI,CAAC,SAAS,CAAC,MAAM;AACnB,aAAO,EAAE,MAAM,WAAW,OAAO,OAAO,cAAc,UAAU,OAAO,SAAS,EAAE;AAAA,IACpF;AAEA,UAAM,eAAe,OAAO,KAAK,MAAM,GAAG,EAAE,IAAI,KAAK,OAAO;AAC5D,WAAO;AAAA,MACL,MAAM;AAAA,MACN,OAAO;AAAA,MACP;AAAA,MACA;AAAA,MACA;AAAA,MACA,KAAK,WAAW,CAAC;AAAA,MACjB;AAAA,IACF;AAAA,EACF;AAGA,MAAI,SAAS,KAAK,KAAK,GAAG;AACxB,WAAO;AAAA,MACL,MAAM;AAAA,MACN,OAAO;AAAA,MACP,cAAc,UAAU,OAAO,QAAQ;AAAA,IACzC;AAAA,EACF;AAGA,MAAI,MAAM,WAAW,GAAG,KAAK,MAAM,WAAW,IAAI,KAAK,MAAM,WAAW,KAAK,KAAK,MAAM,WAAW,GAAG,GAAG;AACvG,WAAO;AAAA,MACL,MAAM;AAAA,MACN,OAAO;AAAA,MACP,cAAc,UAAU,OAAO,OAAO;AAAA,IACxC;AAAA,EACF;AAGA,QAAM,cAAc,MAAM,MAAM,gBAAgB;AAChD,MAAI,eAAe,CAAC,WAAW,KAAK,KAAK,GAAG;AAC1C,UAAM,QAAQ,YAAY,CAAC;AAC3B,UAAM,OAAO,YAAY,CAAC;AAC1B,UAAM,OAAO,YAAY,CAAC;AAC1B,QAAI,CAAC,SAAS,CAAC,MAAM;AACnB,aAAO,EAAE,MAAM,WAAW,OAAO,OAAO,cAAc,UAAU,OAAO,SAAS,EAAE;AAAA,IACpF;AAEA,UAAM,eAAe,OAAO,KAAK,MAAM,GAAG,EAAE,IAAI,KAAK,OAAO;AAC5D,WAAO;AAAA,MACL,MAAM;AAAA,MACN,OAAO,sBAAsB,KAAK,IAAI,IAAI;AAAA,MAC1C;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAGA,QAAM,eAAe,MAAM,MAAM,aAAa;AAC9C,MAAI,cAAc;AAChB,WAAO;AAAA,MACL,MAAM;AAAA,MACN,OAAO;AAAA,MACP,cAAc,UAAU,OAAO,SAAS;AAAA,MACxC,OAAO,aAAa,CAAC;AAAA;AAAA,MACrB,MAAM,aAAa,CAAC;AAAA;AAAA,IACtB;AAAA,EACF;AAGA,MAAI,WAAW,KAAK,KAAK,GAAG;AAC1B,WAAO;AAAA,MACL,MAAM;AAAA,MACN,OAAO;AAAA,MACP,cAAc,UAAU,OAAO,SAAS;AAAA,IAC1C;AAAA,EACF;AAGA,MAAI,YAAY,KAAK,KAAK,KAAK,CAAC,MAAM,SAAS,GAAG,GAAG;AACnD,WAAO;AAAA,MACL,MAAM;AAAA,MACN,OAAO;AAAA,MACP,cAAc,UAAU,OAAO,SAAS;AAAA,IAC1C;AAAA,EACF;AAGA,SAAO;AAAA,IACL,MAAM;AAAA,IACN,OAAO;AAAA,IACP,cAAc,UAAU,OAAO,SAAS;AAAA,EAC1C;AACF;AAqBO,SAAS,oBAAoB,OAAwB;AAC1D,SAAO,sCAAsC,KAAK,KAAK;AACzD;;;ACjPO,IAAM,2BAA2B;AAcjC,IAAM,eAAN,cAA2B,MAAM;AAAA;AAAA,EAEtC;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA,EAEA,YAAY,SAAiB,MAAwB,KAAa,QAAiB;AACjF,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,OAAO;AACZ,SAAK,MAAM;AACX,SAAK,SAAS;AAAA,EAChB;AACF;AAEA,SAAS,aAAa,OAAyB;AAC7C,SAAO,iBAAiB,SAAS,MAAM,SAAS;AAClD;AAuBA,eAAsB,iBACpB,KACA,MACA,YAAY,0BACO;AACnB,MAAI;AACF,WAAO,MAAM,MAAM,KAAK;AAAA,MACtB,GAAG;AAAA,MACH,QAAQ,YAAY,QAAQ,SAAS;AAAA,IACvC,CAAC;AAAA,EACH,SAAS,OAAO;AACd,QAAI,aAAa,KAAK,GAAG;AACvB,YAAM,IAAI,aAAa,2BAA2B,SAAS,MAAM,WAAW,GAAG;AAAA,IACjF;AACA,UAAM,IAAI,aAAa,0BAA0B,WAAW,GAAG;AAAA,EACjE;AACF;AAsBO,SAAS,iBAAiB,UAAoB,KAAuB;AAC1E,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,IAAI,aAAa,8BAA8B,SAAS,MAAM,IAAI,QAAQ,KAAK,SAAS,MAAM;AAAA,EACtG;AACA,SAAO;AACT;AAwBO,SAAS,mBAAmB,OAAwB;AACzD,MAAI,iBAAiB,cAAc;AACjC,QAAI,MAAM,SAAS,WAAW;AAC5B,aAAO;AAAA,IACT;AACA,QAAI,MAAM,SAAS,QAAQ;AACzB,aAAO,wCAAwC,MAAM,UAAU,SAAS;AAAA,IAC1E;AACA,WAAO;AAAA,EACT;AAEA,MAAI,iBAAiB,MAAO,QAAO,MAAM;AACzC,SAAO,OAAO,KAAK;AACrB;;;ACnIA,IAAM,WAAW;AA6BjB,SAAS,gBAAgB,OAAuC;AAC9D,QAAM,QAAQ,MAAM,MAAM,qBAAqB;AAC/C,MAAI,CAAC,MAAO,QAAO;AACnB,SAAO;AAAA,IACL,QAAQ,MAAM,CAAC;AAAA,IACf,MAAM,MAAM,CAAC;AAAA,EACf;AACF;AAEA,SAAS,SAAS,OAAoC;AACpD,SAAO;AAAA,IACL,MAAM,MAAM;AAAA,IACZ,YAAY,MAAM;AAAA,IAClB,aAAa,MAAM;AAAA,IACnB,QAAQ,MAAM;AAAA,IACd,OAAO,MAAM;AAAA,IACb,WAAW,MAAM;AAAA,IACjB,cAAc,MAAM;AAAA,IACpB,MAAM,MAAM;AAAA,IACZ,QAAQ;AAAA,EACV;AACF;AAYO,IAAM,kBAAN,MAAoD;AAAA;AAAA,EAEzD,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASP,MAAM,OAAO,OAAe,QAAQ,IAAkC;AACpE,UAAM,SAAS,IAAI,gBAAgB;AAAA,MACjC,QAAQ;AAAA,MACR,OAAO,OAAO,KAAK;AAAA,MACnB,QAAQ;AAAA,IACV,CAAC;AAED,UAAM,MAAM,GAAG,QAAQ,IAAI,MAAM;AACjC,UAAM,WAAW,iBAAiB,MAAM,iBAAiB,GAAG,GAAG,GAAG;AAClE,UAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,WAAO,KAAK,OAAO,IAAI,QAAQ;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,SAAS,YAAuD;AACpE,UAAM,QAAQ,gBAAgB,UAAU;AACxC,UAAM,cAAc,QAChB,CAAC,MAAM,MAAM,GAAG,MAAM,MAAM,IAAI,MAAM,IAAI,IAAI,UAAU,IACxD,CAAC,UAAU;AAEf,UAAM,OAAO,oBAAI,IAAY;AAC7B,eAAW,QAAQ,aAAa;AAC9B,UAAI,KAAK,IAAI,IAAI,EAAG;AACpB,WAAK,IAAI,IAAI;AAEb,YAAM,SAAS,IAAI,gBAAgB;AAAA,QACjC,QAAQ;AAAA,QACR,OAAO;AAAA,QACP,QAAQ;AAAA,MACV,CAAC;AAED,YAAM,MAAM,GAAG,QAAQ,IAAI,MAAM;AACjC,YAAM,WAAW,iBAAiB,MAAM,iBAAiB,GAAG,GAAG,GAAG;AAClE,YAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,YAAM,QAAQ,KAAK,OAAO;AAAA,QACxB,CAAC,MAAM,EAAE,eAAe,cAAc,IAAI,EAAE,MAAM,IAAI,EAAE,IAAI,OAAO;AAAA,MACrE;AACA,UAAI,OAAO;AACT,eAAO,SAAS,KAAK;AAAA,MACvB;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AACF;;;AC1HA,IAAMC,YAAW;AAgBjB,SAASC,UAAS,OAA0C;AAC1D,SAAO;AAAA,IACL,MAAM,MAAM;AAAA,IACZ,YAAY,IAAI,MAAM,MAAM,IAAI,MAAM,IAAI;AAAA,IAC1C,aAAa,MAAM;AAAA,IACnB,QAAQ,MAAM;AAAA,IACd,OAAO,MAAM,SAAS;AAAA,IACtB,WAAW,MAAM;AAAA,IACjB,cAAc,MAAM;AAAA,IACpB,MAAM;AAAA,IACN,QAAQ;AAAA,EACV;AACF;AAYO,IAAM,kBAAN,MAAoD;AAAA;AAAA,EAEzD,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASP,MAAM,OAAO,OAAe,QAAQ,IAAkC;AACpE,UAAM,SAAS,IAAI,gBAAgB;AAAA,MACjC,GAAG;AAAA,MACH,OAAO,OAAO,KAAK;AAAA,IACrB,CAAC;AAED,UAAM,MAAM,GAAGD,SAAQ,WAAW,MAAM;AACxC,UAAM,WAAW,iBAAiB,MAAM,iBAAiB,GAAG,GAAG,GAAG;AAClE,UAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,WAAO,KAAK,QAAQ,IAAIC,SAAQ;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,SAAS,YAAuD;AACpE,UAAM,UAAU,MAAM,KAAK,OAAO,YAAY,CAAC;AAC/C,WAAO,QAAQ,KAAK,CAAC,MAAM,EAAE,eAAe,UAAU,KAAK;AAAA,EAC7D;AACF;;;AC/DO,IAAM,8BAAN,cAA0C,MAAM;AAAA;AAAA,EAErD;AAAA,EAEA,YAAY,SAAiB,SAAmB;AAC9C,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,UAAU;AAAA,EACjB;AACF;AAuBO,IAAM,oBAAN,MAAwB;AAAA;AAAA,EAErB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBR,YAAY,UAAiC;AAC3C,SAAK,WAAW,YAAY;AAAA,MAC1B,IAAI,gBAAgB;AAAA,MACpB,IAAI,gBAAgB;AAAA,IACtB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBA,MAAM,OAAO,OAAe,QAAQ,IAAkC;AACpE,UAAM,UAAU,MAAM,QAAQ,WAAW,KAAK,SAAS,IAAI,CAAC,YAAY,QAAQ,OAAO,OAAO,KAAK,CAAC,CAAC;AAErG,UAAM,OAA4B,CAAC;AACnC,UAAM,WAAqB,CAAC;AAE5B,eAAW,CAAC,OAAO,MAAM,KAAK,QAAQ,QAAQ,GAAG;AAC/C,YAAM,cAAc,KAAK,SAAS,KAAK,GAAG,QAAQ;AAElD,UAAI,OAAO,WAAW,aAAa;AACjC,aAAK,KAAK,GAAG,OAAO,KAAK;AAAA,MAC3B,OAAO;AACL,cAAM,SAAS,OAAO,kBAAkB,QAAQ,OAAO,OAAO,UAAU,OAAO,OAAO,MAAM;AAC5F,iBAAS,KAAK,GAAG,WAAW,KAAK,MAAM,EAAE;AAAA,MAC3C;AAAA,IACF;AAEA,QAAI,KAAK,WAAW,KAAK,SAAS,SAAS,GAAG;AAC5C,YAAM,IAAI,4BAA4B,mCAAmC,QAAQ;AAAA,IACnF;AAGA,UAAM,OAAO,oBAAI,IAA+B;AAChD,eAAW,UAAU,MAAM;AACzB,YAAM,WAAW,KAAK,IAAI,OAAO,UAAU;AAC3C,UAAI,CAAC,YAAY,OAAO,QAAQ,SAAS,OAAO;AAC9C,aAAK,IAAI,OAAO,YAAY,MAAM;AAAA,MACpC;AAAA,IACF;AAGA,UAAM,eAAe,MAAM,KAAK,KAAK,OAAO,CAAC;AAC7C,iBAAa,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;AAE7C,WAAO,aAAa,MAAM,GAAG,KAAK;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,MAAM,SAAS,YAAuD;AACpE,UAAM,WAAqB,CAAC;AAE5B,eAAW,WAAW,KAAK,UAAU;AACnC,UAAI;AACF,cAAM,SAAS,MAAM,QAAQ,SAAS,UAAU;AAChD,YAAI,OAAQ,QAAO;AAAA,MACrB,SAAS,OAAO;AACd,cAAM,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACpE,iBAAS,KAAK,GAAG,QAAQ,IAAI,KAAK,MAAM,EAAE;AAAA,MAC5C;AAAA,IACF;AAEA,QAAI,SAAS,WAAW,KAAK,SAAS,UAAU,KAAK,SAAS,SAAS,GAAG;AACxE,YAAM,IAAI,4BAA4B,mCAAmC,QAAQ;AAAA,IACnF;AAEA,WAAO;AAAA,EACT;AACF;;;AC1JA,SAAS,qBAAqB;AAC9B,SAAS,cAAAC,cAAY,aAAa,oBAAoB;AACtD,SAAS,YAAAC,WAAU,WAAAC,UAAS,QAAAC,aAAY;AAWxC,IAAMC,WAAU,cAAc,YAAY,GAAG;AAsBtC,SAAS,sBAAsB,MAA4B;AAEhE,MAAI;AAEJ,MAAI;AACF,UAAMA,SAAQ,IAAI;AAAA,EACpB,QAAQ;AACN,UAAM,IAAI,MAAM,4CAA4C,IAAI,EAAE;AAAA,EACpE;AAGA,QAAM,kBAAkB;AAAA,IACtB;AAAA,IAAc;AAAA,IAAY;AAAA,IAAgB;AAAA,IAAe;AAAA,IACzD;AAAA,IAAiB;AAAA,IAAuB;AAAA,IAAwB;AAAA,IAChE;AAAA,IAAgB;AAAA,IAAc;AAAA,IAC9B;AAAA,IAAuB;AAAA,IAAyB;AAAA,IAChD;AAAA,IAAiB;AAAA,IAAmB;AAAA,IACpC;AAAA,IAA4B;AAAA,IAAe;AAAA,EAC7C;AAEA,aAAW,UAAU,iBAAiB;AACpC,QAAI,OAAO,IAAI,MAAM,MAAM,YAAY;AACrC,YAAM,IAAI;AAAA,QACR,oBAAoB,IAAI,wCAAwC,MAAM;AAAA,MACxE;AAAA,IACF;AAAA,EACF;AAEA,MAAI,CAAC,IAAI,WAAW,OAAO,IAAI,YAAY,UAAU;AACnD,UAAM,IAAI,MAAM,oBAAoB,IAAI,gCAAgC;AAAA,EAC1E;AAEA,MAAI,CAAC,IAAI,eAAe,OAAO,IAAI,gBAAgB,UAAU;AAC3D,UAAM,IAAI,MAAM,oBAAoB,IAAI,oCAAoC;AAAA,EAC9E;AAEA,SAAO;AACT;AA2BO,SAAS,sBAAsB,MAA4B;AAChE,QAAM,cAAcD,MAAK,MAAM,aAAa;AAC5C,MAAI,CAACH,aAAW,WAAW,GAAG;AAC5B,UAAM,IAAI,MAAM,2BAA2B,IAAI,EAAE;AAAA,EACnD;AAEA,QAAM,cAAc,KAAK,MAAM,aAAa,aAAa,OAAO,CAAC;AACjE,QAAM,UAA+B,YAAY,UAAU,CAAC;AAC5D,QAAM,UAAkB,YAAY,WAAW;AAG/C,QAAM,eAAeG,MAAK,MAAM,UAAU,eAAe;AACzD,MAAI;AACJ,MAAIH,aAAW,YAAY,GAAG;AAC5B,eAAW,KAAK,MAAM,aAAa,cAAc,OAAO,CAAC;AAAA,EAC3D,OAAO;AACL,eAAW;AAAA,MACT,SAAS;AAAA,MACT,OAAO,CAAC;AAAA,MACR,iBAAiB,EAAE,cAAc,CAAC,GAAG,YAAY,CAAC,GAAG,aAAa,CAAC,EAAE;AAAA,MACrE,QAAQ,CAAC;AAAA,IACX;AAAA,EACF;AAGA,QAAM,cAAcG,MAAK,MAAM,UAAU;AACzC,QAAM,WAAW,oBAAI,IAAiC;AACtD,MAAIH,aAAW,WAAW,GAAG;AAC3B,eAAW,QAAQ,YAAY,WAAW,GAAG;AAC3C,UAAI,CAAC,KAAK,SAAS,OAAO,EAAG;AAC7B,UAAI;AACF,cAAM,UAA+B,KAAK;AAAA,UACxC,aAAaG,MAAK,aAAa,IAAI,GAAG,OAAO;AAAA,QAC/C;AACA,iBAAS,IAAI,QAAQ,MAAM,OAAO;AAAA,MACpC,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF;AAGA,QAAM,WAAW,oBAAI,IAA+B;AACpD,aAAW,SAAS,SAAS;AAC3B,aAAS,IAAI,MAAM,MAAM,KAAK;AAAA,EAChC;AAIA,WAASE,aAAY,MAAsB;AACzC,UAAM,QAAQ,SAAS,IAAI,IAAI;AAC/B,QAAI,OAAO;AACT,aAAOH,SAAQC,MAAK,MAAM,MAAM,IAAI,CAAC;AAAA,IACvC;AACA,WAAOA,MAAK,MAAM,UAAU,IAAI;AAAA,EAClC;AAEA,WAAS,YAAY,OAAiB,UAAU,oBAAI,IAAY,GAAa;AAC3E,UAAM,SAAmB,CAAC;AAC1B,eAAW,QAAQ,OAAO;AACxB,UAAI,QAAQ,IAAI,IAAI,EAAG;AACvB,cAAQ,IAAI,IAAI;AAEhB,YAAM,QAAQ,SAAS,IAAI,IAAI;AAC/B,UAAI,SAAS,MAAM,aAAa,SAAS,GAAG;AAC1C,eAAO,KAAK,GAAG,YAAY,MAAM,cAAc,OAAO,CAAC;AAAA,MACzD;AACA,aAAO,KAAK,IAAI;AAAA,IAClB;AACA,WAAO;AAAA,EACT;AAEA,WAAS,qBAAqB,MAAc,UAAU,oBAAI,IAAY,GAAa;AACjF,QAAI,QAAQ,IAAI,IAAI,EAAG,QAAO,CAAC;AAC/B,YAAQ,IAAI,IAAI;AAEhB,UAAM,UAAU,SAAS,IAAI,IAAI;AACjC,QAAI,CAAC,QAAS,QAAO,CAAC;AAEtB,QAAI,SAAmB,CAAC;AACxB,QAAI,QAAQ,SAAS;AACnB,eAAS,qBAAqB,QAAQ,SAAS,OAAO;AAAA,IACxD;AACA,WAAO,KAAK,GAAG,QAAQ,MAAM;AAG7B,WAAO,YAAY,CAAC,GAAG,IAAI,IAAI,MAAM,CAAC,CAAC;AAAA,EACzC;AAEA,WAAS,cAAc,KAAa,KAAuB;AACzD,QAAI,CAACH,aAAW,GAAG,EAAG,QAAO,CAAC;AAC9B,WAAO,YAAY,GAAG,EACnB,OAAO,OAAK,EAAE,SAAS,GAAG,CAAC,EAC3B,IAAI,OAAKC,UAAS,GAAG,GAAG,CAAC;AAAA,EAC9B;AAIA,QAAM,UAAwB;AAAA,IAC5B;AAAA,IACA,aAAa;AAAA,IACb,QAAQ;AAAA,IACR;AAAA,IAEA,aAAuB;AACrB,aAAO,QAAQ,IAAI,OAAK,EAAE,IAAI;AAAA,IAChC;AAAA,IAEA,SAAS,MAA6C;AACpD,aAAO,SAAS,IAAI,IAAI;AAAA,IAC1B;AAAA,IAEA,aAAa,MAAsB;AACjC,YAAM,QAAQ,SAAS,IAAI,IAAI;AAC/B,UAAI,OAAO;AACT,eAAOE,MAAK,MAAM,MAAM,IAAI;AAAA,MAC9B;AACA,aAAOA,MAAK,MAAM,UAAU,MAAM,UAAU;AAAA,IAC9C;AAAA,IAEA,aAAAE;AAAA,IAEA,iBAAiB,MAAsB;AACrC,YAAM,YAAY,QAAQ,aAAa,IAAI;AAC3C,UAAI,CAACL,aAAW,SAAS,GAAG;AAC1B,cAAM,IAAI,MAAM,4BAA4B,SAAS,EAAE;AAAA,MACzD;AACA,aAAO,aAAa,WAAW,OAAO;AAAA,IACxC;AAAA,IAEA,gBAAqC;AACnC,aAAO,QAAQ,OAAO,OAAK,EAAE,IAAI;AAAA,IACnC;AAAA,IAEA,oBAAoB,UAA8D;AAChF,aAAO,QAAQ,OAAO,OAAK,EAAE,aAAa,QAAQ;AAAA,IACpD;AAAA,IAEA,qBAAqB,MAAwB;AAC3C,aAAO,SAAS,IAAI,IAAI,GAAG,gBAAgB,CAAC;AAAA,IAC9C;AAAA,IAEA,sBAAsB,OAA2B;AAC/C,aAAO,YAAY,KAAK;AAAA,IAC1B;AAAA,IAEA,eAAyB;AACvB,aAAO,CAAC,GAAG,SAAS,KAAK,CAAC;AAAA,IAC5B;AAAA,IAEA,WAAW,MAA+C;AACxD,aAAO,SAAS,IAAI,IAAI;AAAA,IAC1B;AAAA,IAEA,eAAe,MAAwB;AACrC,aAAO,qBAAqB,IAAI;AAAA,IAClC;AAAA,IAEA,sBAAgC;AAC9B,aAAO,cAAcG,MAAK,MAAM,UAAU,SAAS,GAAG,KAAK;AAAA,IAC7D;AAAA,IAEA,sBAAsB,MAAkC;AACtD,YAAM,eAAeA,MAAK,MAAM,UAAU,WAAW,GAAG,IAAI,KAAK;AACjE,aAAOH,aAAW,YAAY,IAAI,eAAe;AAAA,IACnD;AAAA,IAEA,mBAAmB,MAAkC;AACnD,YAAM,eAAe,QAAQ,sBAAsB,IAAI;AACvD,UAAI,CAAC,aAAc,QAAO;AAC1B,aAAO,aAAa,cAAc,OAAO;AAAA,IAC3C;AAAA,IAEA,gBAA0B;AAExB,YAAM,gBAAgB,cAAcG,MAAK,MAAM,WAAW,GAAG,KAAK;AAClE,UAAI,cAAc,SAAS,EAAG,QAAO;AACrC,aAAO,cAAcA,MAAK,MAAM,UAAU,WAAW,GAAG,KAAK;AAAA,IAC/D;AAAA,IAEA,gBAAgB,MAAkC;AAEhD,YAAM,WAAWA,MAAK,MAAM,aAAa,GAAG,IAAI,KAAK;AACrD,UAAIH,aAAW,QAAQ,EAAG,QAAO;AACjC,YAAM,aAAaG,MAAK,MAAM,UAAU,aAAa,GAAG,IAAI,KAAK;AACjE,aAAOH,aAAW,UAAU,IAAI,aAAa;AAAA,IAC/C;AAAA,IAEA,aAAa,MAAkC;AAC7C,YAAM,eAAe,QAAQ,gBAAgB,IAAI;AACjD,UAAI,CAAC,aAAc,QAAO;AAC1B,aAAO,aAAa,cAAc,OAAO;AAAA,IAC3C;AAAA,IAEA,yBAAyB,MAA4C;AACnE,YAAM,QAAQ,SAAS,IAAI,IAAI;AAC/B,UAAI,CAAC,OAAO;AACV,eAAO;AAAA,UACL,OAAO;AAAA,UACP,QAAQ,CAAC,EAAE,OAAO,SAAS,OAAO,QAAQ,SAAS,oBAAoB,IAAI,GAAG,CAAC;AAAA,QACjF;AAAA,MACF;AAEA,YAAM,SAAwC,CAAC;AAE/C,UAAI,CAAC,MAAM,MAAM;AACf,eAAO,KAAK,EAAE,OAAO,SAAS,OAAO,QAAQ,SAAS,eAAe,CAAC;AAAA,MACxE;AACA,UAAI,CAAC,MAAM,aAAa;AACtB,eAAO,KAAK,EAAE,OAAO,SAAS,OAAO,eAAe,SAAS,sBAAsB,CAAC;AAAA,MACtF;AACA,UAAI,CAAC,MAAM,SAAS;AAClB,eAAO,KAAK,EAAE,OAAO,QAAQ,OAAO,WAAW,SAAS,kBAAkB,CAAC;AAAA,MAC7E;AAGA,YAAM,YAAYG,MAAK,MAAM,MAAM,IAAI;AACvC,UAAI,CAACH,aAAW,SAAS,GAAG;AAC1B,eAAO,KAAK,EAAE,OAAO,SAAS,OAAO,QAAQ,SAAS,yBAAyB,MAAM,IAAI,GAAG,CAAC;AAAA,MAC/F;AAEA,aAAO;AAAA,QACL,OAAO,CAAC,OAAO,KAAK,OAAK,EAAE,UAAU,OAAO;AAAA,QAC5C;AAAA,MACF;AAAA,IACF;AAAA,IAEA,cAAyD;AACvD,YAAM,UAAU,oBAAI,IAA0C;AAC9D,iBAAW,SAAS,SAAS;AAC3B,gBAAQ,IAAI,MAAM,MAAM,QAAQ,yBAAyB,MAAM,IAAI,CAAC;AAAA,MACtE;AACA,aAAO;AAAA,IACT;AAAA,IAEA,oBAAgD;AAC9C,aAAO,SAAS;AAAA,IAClB;AAAA,EACF;AAEA,SAAO;AACT;;;AC5VA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUA,SAAS,cAAAM,oBAAkB;AAC3B,SAAS,QAAAC,aAAY;AAarB,IAAI,WAAgC;AAoB7B,SAAS,qBAAqB,SAA6B;AAChE,aAAW;AACb;AAsBO,SAAS,6BAA6B,MAAoB;AAE/D,QAAM,YAAYC,MAAK,MAAM,UAAU;AACvC,MAAIC,aAAW,SAAS,GAAG;AACzB,eAAW,sBAAsB,IAAI;AACrC;AAAA,EACF;AAGA,aAAW,sBAAsB,IAAI;AACvC;AAiBO,SAAS,yBAA+B;AAC7C,aAAW;AACb;AAUA,SAAS,kBAAuC;AAE9C,QAAM,UAAU,QAAQ,IAAI,qBAAqB;AACjD,MAAI,WAAWA,aAAW,OAAO,GAAG;AAClC,QAAI;AACF,YAAM,YAAYD,MAAK,SAAS,UAAU;AAC1C,UAAIC,aAAW,SAAS,GAAG;AACzB,eAAO,sBAAsB,OAAO;AAAA,MACtC;AACA,UAAIA,aAAWD,MAAK,SAAS,aAAa,CAAC,GAAG;AAC5C,eAAO,sBAAsB,OAAO;AAAA,MACtC;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,SAAO;AACT;AAIA,SAAS,aAA2B;AAClC,MAAI,CAAC,UAAU;AACb,UAAM,aAAa,gBAAgB;AACnC,QAAI,YAAY;AACd,iBAAW;AAAA,IACb;AAAA,EACF;AAEA,MAAI,CAAC,UAAU;AACb,UAAM,IAAI;AAAA,MACR;AAAA,IAEF;AAAA,EACF;AAEA,SAAO;AACT;AAwBO,SAAS,qBAA8B;AAC5C,MAAI;AACF,eAAW;AACX,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAmBO,SAAS,YAAiC;AAC/C,SAAO,WAAW,EAAE;AACtB;AAmBO,SAAS,cAAoC;AAClD,SAAO,WAAW,EAAE;AACtB;AAmBO,SAAS,aAAuB;AACrC,SAAO,WAAW,EAAE,WAAW;AACjC;AAsBO,SAAS,SAAS,MAA6C;AACpE,SAAO,WAAW,EAAE,SAAS,IAAI;AACnC;AAoBO,SAAS,aAAa,MAAsB;AACjD,SAAO,WAAW,EAAE,aAAa,IAAI;AACvC;AAoBO,SAAS,YAAY,MAAsB;AAChD,SAAO,WAAW,EAAE,YAAY,IAAI;AACtC;AAoBO,SAAS,iBAAiB,MAAsB;AACrD,SAAO,WAAW,EAAE,iBAAiB,IAAI;AAC3C;AAmBO,SAAS,gBAAqC;AACnD,SAAO,WAAW,EAAE,cAAc;AACpC;AAmBO,SAAS,oBAAoB,UAA8D;AAChG,SAAO,WAAW,EAAE,oBAAoB,QAAQ;AAClD;AAoBO,SAAS,qBAAqB,MAAwB;AAC3D,SAAO,WAAW,EAAE,qBAAqB,IAAI;AAC/C;AAqBO,SAAS,sBAAsB,OAA2B;AAC/D,SAAO,WAAW,EAAE,sBAAsB,KAAK;AACjD;AAmBO,SAAS,eAAyB;AACvC,SAAO,WAAW,EAAE,aAAa;AACnC;AAuBO,SAAS,WAAW,MAA+C;AACxE,SAAO,WAAW,EAAE,WAAW,IAAI;AACrC;AAoBO,SAAS,eAAe,MAAwB;AACrD,SAAO,WAAW,EAAE,eAAe,IAAI;AACzC;AAmBO,SAAS,sBAAgC;AAC9C,SAAO,WAAW,EAAE,oBAAoB;AAC1C;AAmBO,SAAS,sBAAsB,MAAkC;AACtE,SAAO,WAAW,EAAE,sBAAsB,IAAI;AAChD;AAsBO,SAAS,mBAAmB,MAAkC;AACnE,SAAO,WAAW,EAAE,mBAAmB,IAAI;AAC7C;AAmBO,SAAS,gBAA0B;AACxC,SAAO,WAAW,EAAE,cAAc;AACpC;AAmBO,SAAS,gBAAgB,MAAkC;AAChE,SAAO,WAAW,EAAE,gBAAgB,IAAI;AAC1C;AAsBO,SAAS,aAAa,MAAkC;AAC7D,SAAO,WAAW,EAAE,aAAa,IAAI;AACvC;AAsBO,SAAS,yBAAyB,MAA4C;AACnF,SAAO,WAAW,EAAE,yBAAyB,IAAI;AACnD;AAqBO,SAAS,cAAyD;AACvE,SAAO,WAAW,EAAE,YAAY;AAClC;AAmBO,SAAS,oBAAgD;AAC9D,SAAO,WAAW,EAAE,kBAAkB;AACxC;AAmBO,SAAS,aAAqB;AACnC,SAAO,WAAW,EAAE;AACtB;AAmBO,SAAS,iBAAyB;AACvC,SAAO,WAAW,EAAE;AACtB;;;AChtBA,SAAS,YAAAE,WAAU,eAAe;AAClC,SAAS,cAAAC,oBAAkB;AAC3B,SAAS,QAAAC,aAAa;AACtB,OAAO,YAAY;AAwBnB,eAAsB,eAAe,UAAiD;AACpF,MAAI;AACF,UAAM,UAAU,MAAMF,UAAS,UAAU,OAAO;AAChD,UAAM,EAAE,KAAK,IAAI,OAAO,OAAO;AAE/B,QAAI,CAAC,KAAK,QAAQ,CAAC,KAAK,aAAa;AACnC,aAAO;AAAA,IACT;AAEA,UAAM,eAAe,KAAK,eAAe,KAAK,KAAK;AAEnD,WAAO;AAAA,MACL,MAAM,OAAO,KAAK,IAAI;AAAA,MACtB,aAAa,OAAO,KAAK,WAAW;AAAA,MACpC,SAAS,KAAK,UAAU,OAAO,KAAK,OAAO,IAAI;AAAA,MAC/C,eAAe,KAAK,gBAAgB,OAAO,KAAK,aAAa,IAAI;AAAA,MACjE,UAAU,KAAK;AAAA,MACf,cAAc,OAAO,iBAAiB,WAClC,aAAa,MAAM,KAAK,IACxB,MAAM,QAAQ,YAAY,IACxB,aAAa,IAAI,MAAM,IACvB;AAAA,MACN,SAAS,KAAK,UAAU,OAAO,KAAK,OAAO,IAAI;AAAA,IACjD;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAwBA,eAAsB,cAAc,UAA8C;AAChF,QAAM,YAAYE,MAAK,UAAU,UAAU;AAC3C,MAAI,CAACD,aAAW,SAAS,EAAG,QAAO;AAEnC,QAAM,WAAW,MAAM,eAAe,SAAS;AAC/C,MAAI,CAAC,SAAU,QAAO;AAEtB,SAAO;AAAA,IACL,MAAM,SAAS;AAAA,IACf,YAAY,SAAS;AAAA,IACrB,MAAM;AAAA,IACN;AAAA,EACF;AACF;AAsBA,eAAsB,eAAe,SAAwC;AAC3E,MAAI,CAACA,aAAW,OAAO,EAAG,QAAO,CAAC;AAElC,QAAM,UAAU,MAAM,QAAQ,SAAS,EAAE,eAAe,KAAK,CAAC;AAC9D,QAAM,SAAuB,CAAC;AAE9B,aAAW,SAAS,SAAS;AAC3B,QAAI,CAAC,MAAM,YAAY,KAAK,CAAC,MAAM,eAAe,EAAG;AAErD,UAAM,WAAWC,MAAK,SAAS,MAAM,IAAI;AACzC,UAAM,QAAQ,MAAM,cAAc,QAAQ;AAC1C,QAAI,OAAO;AACT,aAAO,KAAK,KAAK;AAAA,IACnB;AAAA,EACF;AAEA,SAAO;AACT;AAoBA,eAAsB,oBAAoB,MAAuC;AAC/E,QAAM,MAAoB,CAAC;AAC3B,QAAM,OAAO,oBAAI,IAAY;AAE7B,aAAW,OAAO,MAAM;AACtB,UAAM,SAAS,MAAM,eAAe,GAAG;AACvC,eAAW,SAAS,QAAQ;AAC1B,UAAI,CAAC,KAAK,IAAI,MAAM,IAAI,GAAG;AACzB,aAAK,IAAI,MAAM,IAAI;AACnB,YAAI,KAAK,KAAK;AAAA,MAChB;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;;;AClKA,SAAS,iBAAiB;AAC1B,SAAS,gBAAgB;AACzB,SAAS,iBAAiB;AAE1B,IAAM,gBAAgB,UAAU,QAAQ;AAgCxC,eAAsB,mBACpB,WACA,YACA,QACA,YACA,QACA,eACA,UACA,YACA,SACe;AACf,QAAM,eAAe,CAAC,SAAS;AAC7B,UAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AACnC,UAAM,WAAW,KAAK,OAAO,SAAS;AAEtC,SAAK,OAAO,SAAS,IAAI;AAAA,MACvB,MAAM;AAAA,MACN,YAAY,UAAU,cAAc;AAAA,MACpC,QAAQ,UAAU,UAAU;AAAA,MAC5B,YAAY,UAAU,cAAc;AAAA,MACpC,SAAS,WAAW,UAAU;AAAA,MAC9B,aAAa,UAAU,eAAe;AAAA,MACtC,WAAW;AAAA,MACX,QAAQ,CAAC,GAAG,oBAAI,IAAI,CAAC,GAAI,UAAU,UAAU,CAAC,GAAI,GAAG,MAAM,CAAC,CAAC;AAAA,MAC7D;AAAA,MACA,UAAU,UAAU,YAAY;AAAA,MAChC,YAAY,UAAU,cAAc;AAAA,IACtC;AAAA,EACF,CAAC;AACH;AAoBA,eAAsB,oBAAoB,WAAqC;AAC7E,MAAI,UAAU;AACd,QAAM,eAAe,CAAC,SAAS;AAC7B,QAAI,EAAE,aAAa,KAAK,QAAS;AACjC,WAAO,KAAK,OAAO,SAAS;AAC5B,cAAU;AAAA,EACZ,CAAC;AACD,SAAO;AACT;AAoBA,eAAsB,mBAAuD;AAC3E,QAAM,OAAO,MAAM,aAAa;AAChC,SAAO,KAAK;AACd;AAGA,eAAe,eACb,SACA,KACwB;AACxB,MAAI;AACF,UAAM,MAAM,UAAU;AACtB,UAAM,SAAS,OAAO;AAEtB,UAAM,OAAO,WAAW,SACpB,CAAC,SAAS,MAAM,IAChB,CAAC,UAAU,SAAS,MAAM;AAC9B,UAAM,SAAS,MAAM,IAAI,WAAW,IAAI;AACxC,UAAM,YAAY,OAAO,KAAK,EAAE,MAAM,IAAI,EAAE,CAAC;AAC7C,QAAI,CAAC,UAAW,QAAO;AACvB,UAAM,MAAM,UAAU,MAAM,GAAI,EAAE,CAAC;AACnC,WAAO,OAAO;AAAA,EAChB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAGA,eAAe,0BAA0B,aAA6C;AACpF,MAAI;AACF,UAAM,EAAE,OAAO,IAAI,MAAM,cAAc,OAAO,CAAC,QAAQ,aAAa,SAAS,CAAC;AAC9E,WAAO,OAAO,KAAK,KAAK;AAAA,EAC1B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAuBA,eAAsB,iBAAiB,WAKpC;AACD,QAAM,OAAO,MAAM,aAAa;AAChC,QAAM,QAAQ,KAAK,OAAO,SAAS;AACnC,MAAI,CAAC,OAAO;AACV,WAAO,EAAE,WAAW,OAAO,QAAQ,UAAU;AAAA,EAC/C;AAGA,MAAI,MAAM,eAAe,YAAY,MAAM,eAAe,YAAY,MAAM,eAAe,WAAW;AACpG,WAAO;AAAA,MACL,WAAW;AAAA,MACX,gBAAgB,MAAM;AAAA,MACtB,QAAQ;AAAA,IACV;AAAA,EACF;AAEA,QAAM,SAAS,YAAY,MAAM,MAAM;AACvC,MAAI,CAAC,OAAO,OAAO;AACjB,WAAO;AAAA,MACL,WAAW;AAAA,MACX,gBAAgB,MAAM;AAAA,MACtB,QAAQ;AAAA,IACV;AAAA,EACF;AAEA,MAAI,MAAM,eAAe,WAAW;AAClC,UAAM,cAAc,OAAO;AAC3B,UAAM,gBAAgB,MAAM,0BAA0B,WAAW;AACjE,QAAI,CAAC,eAAe;AAClB,aAAO;AAAA,QACL,WAAW;AAAA,QACX,gBAAgB,MAAM;AAAA,QACtB,QAAQ;AAAA,MACV;AAAA,IACF;AACA,UAAMC,kBAAiB,MAAM;AAC7B,UAAMC,aAAY,CAACD,mBAAkBA,oBAAmB;AACxD,WAAO;AAAA,MACL,WAAAC;AAAA,MACA,gBAAgBD,mBAAkB;AAAA,MAClC;AAAA,MACA,QAAQC,aAAY,qBAAqB;AAAA,IAC3C;AAAA,EACF;AAEA,MAAI,CAAC,OAAO,MAAM;AAChB,WAAO;AAAA,MACL,WAAW;AAAA,MACX,gBAAgB,MAAM;AAAA,MACtB,QAAQ;AAAA,IACV;AAAA,EACF;AAEA,QAAM,OAAO,OAAO,SAAS,WAAW,eAAe;AACvD,QAAM,UAAU,WAAW,IAAI,IAAI,OAAO,KAAK,IAAI,OAAO,IAAI;AAC9D,QAAM,YAAY,MAAM,eAAe,SAAS,OAAO,GAAG;AAE1D,MAAI,CAAC,WAAW;AACd,WAAO;AAAA,MACL,WAAW;AAAA,MACX,gBAAgB,MAAM;AAAA,MACtB,QAAQ;AAAA,IACV;AAAA,EACF;AAEA,QAAM,iBAAiB,MAAM;AAC7B,QAAM,YAAY,CAAC,kBAAkB,CAAC,UAAU,WAAW,eAAe,MAAM,GAAG,CAAC,CAAC;AAErF,SAAO;AAAA,IACL;AAAA,IACA,gBAAgB,kBAAkB;AAAA,IAClC,eAAe,UAAU,MAAM,GAAG,EAAE;AAAA,IACpC,QAAQ,YAAY,qBAAqB;AAAA,EAC3C;AACF;AAuBA,eAAsB,uBAKlB;AACF,QAAM,OAAO,MAAM,aAAa;AAChC,QAAM,aAAa,OAAO,KAAK,KAAK,MAAM;AAE1C,QAAM,UAA+B,CAAC;AACtC,QAAM,QAAQ,IAAI,WAAW,IAAI,OAAO,SAAS;AAC/C,YAAQ,IAAI,IAAI,MAAM,iBAAiB,IAAI;AAAA,EAC7C,CAAC,CAAC;AAEF,SAAO;AACT;;;AC9RO,IAAM,6BAA6B;AAAA,EACxC,eAAe;AAAA,EACf,YAAY;AAAA,EACZ,oBAAoB;AAAA,EACpB,mBAAmB;AACrB;AAgQA,IAAM,kBAAyC;AAAA,EAC7C,eAAe;AAAA,EACf,aAAa;AAAA,EACb,iBAAiB;AAAA,EACjB,aAAa;AAAA,EACb,eAAe;AAAA,EACf,mBAAmB;AAAA,EACnB,qBAAqB;AAAA,EACrB,gBAAgB;AAAA,EAChB,wBAAwB;AAC1B;AAEA,IAAM,yBAAyB,CAAC,YAAY,SAAS,QAAQ,QAAQ,WAAW,aAAa;AAC7F,IAAM,yBAAyB,CAAC,YAAY,UAAU,SAAS,UAAU,aAAa,aAAa;AAqB5F,SAAS,sBAAsB,OAAyB;AAC7D,SAAO,MACJ,MAAM,GAAG,EACT,IAAI,CAAC,SAAS,KAAK,KAAK,EAAE,YAAY,CAAC,EACvC,OAAO,OAAO;AACnB;AAEA,SAAS,cAAc,OAA0B;AAC/C,MAAI,UAAU,OAAW,QAAO,CAAC;AAEjC,MAAI,EAAE,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,GAAI,QAAO,CAAC;AAElE,QAAM,SAAS,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK;AACpD,QAAM,YAAY,OAAO,QAAQ,CAAC,SAAU,OAAO,SAAS,WAAW,sBAAsB,IAAI,IAAI,CAAC,CAAE;AACxG,SAAO,MAAM,KAAK,IAAI,IAAI,SAAS,CAAC,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,cAAc,CAAC,CAAC;AACzE;AAEA,SAAS,oBAAoB,OAA6C;AACxE,QAAM,QAAQ,OAAO,MAAM,UAAU,WAAW,MAAM,MAAM,KAAK,IAAI;AACrE,MAAI,MAAM,SAAS,EAAG,QAAO;AAE7B,QAAM,QAAQ,CAAC,MAAM,UAAU,MAAM,QAAQ,MAAM,OAAO;AAC1D,SAAO,MAAM,KAAK,CAAC,SAAS,cAAc,IAAI,EAAE,SAAS,CAAC;AAC5D;AA2BO,SAAS,+BAA+B,OAAoE;AACjH,QAAM,SAA0C,CAAC;AAEjD,MAAI,MAAM,UAAU,UAAa,OAAO,MAAM,UAAU,UAAU;AAChE,WAAO,KAAK;AAAA,MACV,MAAM,2BAA2B;AAAA,MACjC,OAAO;AAAA,MACP,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAEA,MAAI,MAAM,aAAa,UAAa,EAAE,OAAO,MAAM,aAAa,YAAY,MAAM,QAAQ,MAAM,QAAQ,IAAI;AAC1G,WAAO,KAAK;AAAA,MACV,MAAM,2BAA2B;AAAA,MACjC,OAAO;AAAA,MACP,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAEA,MAAI,MAAM,WAAW,UAAa,EAAE,OAAO,MAAM,WAAW,YAAY,MAAM,QAAQ,MAAM,MAAM,IAAI;AACpG,WAAO,KAAK;AAAA,MACV,MAAM,2BAA2B;AAAA,MACjC,OAAO;AAAA,MACP,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAEA,MAAI,MAAM,YAAY,UAAa,EAAE,OAAO,MAAM,YAAY,YAAY,MAAM,QAAQ,MAAM,OAAO,IAAI;AACvG,WAAO,KAAK;AAAA,MACV,MAAM,2BAA2B;AAAA,MACjC,OAAO;AAAA,MACP,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAEA,QAAM,WAAW,cAAc,MAAM,QAAQ;AAC7C,QAAM,SAAS,cAAc,MAAM,MAAM;AACzC,QAAM,UAAU,cAAc,MAAM,OAAO;AAC3C,QAAM,WAAW,SAAS,KAAK,CAAC,SAAS,QAAQ,SAAS,IAAI,CAAC,KAAK,OAAO,KAAK,CAAC,SAAS,QAAQ,SAAS,IAAI,CAAC;AAChH,MAAI,UAAU;AACZ,WAAO,KAAK;AAAA,MACV,MAAM,2BAA2B;AAAA,MACjC,OAAO;AAAA,MACP,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAEA,MAAI,OAAO,WAAW,KAAK,CAAC,oBAAoB,KAAK,GAAG;AACtD,WAAO,KAAK;AAAA,MACV,MAAM,2BAA2B;AAAA,MACjC,OAAO;AAAA,MACP,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAEA,SAAO;AAAA,IACL,OAAO,OAAO,WAAW;AAAA,IACzB;AAAA,EACF;AACF;AA0BO,SAAS,gCAAgC,OAAsE;AACpH,QAAM,SAAS,MAAM,SAAS,IAAI,KAAK,EAAE,YAAY;AACrD,SAAO;AAAA,IACL;AAAA,IACA,aAAa,QAAQ,MAAM,KAAK,IAAI,IAAI,sBAAsB,MAAM,QAAQ,QAAQ,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,cAAc,CAAC,CAAC,IAAI,CAAC;AAAA,IAClI,UAAU,cAAc,MAAM,QAAQ;AAAA,IACtC,QAAQ,cAAc,MAAM,MAAM;AAAA,IAClC,SAAS,cAAc,MAAM,OAAO;AAAA,EACtC;AACF;AAEA,SAAS,aAAa,UAAkB,SAA2B;AACjE,MAAI,QAAQ;AACZ,aAAW,UAAU,SAAS;AAC5B,QAAI,SAAS,SAAS,MAAM,GAAG;AAC7B,eAAS;AAAA,IACX;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,WAAW,OAAuB;AACzC,SAAO,OAAO,MAAM,QAAQ,CAAC,CAAC;AAChC;AAEA,SAAS,gBAAgB,OAAkC;AACzD,SAAO,GAAG,MAAM,IAAI,IAAI,MAAM,UAAU,IAAI,MAAM,WAAW,IAAI,MAAM,MAAM,GAAG,YAAY;AAC9F;AA4BO,SAAS,yBACd,OACA,UACA,UAAiC,CAAC,GACP;AAC3B,QAAM,UAAU,EAAE,GAAG,iBAAiB,GAAG,QAAQ,QAAQ;AACzD,QAAM,iBAAiB,QAAQ,iBAAiB,wBAAwB,IAAI,CAAC,WAAW,OAAO,YAAY,CAAC;AAC5G,QAAM,iBAAiB,QAAQ,iBAAiB,wBAAwB,IAAI,CAAC,WAAW,OAAO,YAAY,CAAC;AAC5G,QAAM,OAAO,gBAAgB,KAAK;AAClC,QAAM,UAAkC,CAAC;AACzC,QAAM,YAAsB,CAAC;AAE7B,QAAM,kBAAkB,aAAa,MAAM,SAAS,QAAQ;AAC5D,QAAM,kBAAkB,KAAK,IAAI,SAAS,SAAS,SAAS,iBAAiB,CAAC;AAC9E,QAAM,gBAAgB,aAAa,MAAM,SAAS,MAAM;AACxD,QAAM,eAAe,aAAa,MAAM,SAAS,WAAW;AAC5D,QAAM,iBAAiB,aAAa,MAAM,SAAS,OAAO;AAC1D,QAAM,gBAAgB,aAAa,MAAM,aAAa;AACtD,QAAM,gBAAgB,aAAa,MAAM,aAAa;AACtD,QAAM,iBAAiB,MAAM,YAAY,KAAK,EAAE,UAAU,KAAK,IAAI;AACnE,QAAM,cAAc,KAAK,MAAM,MAAM,QAAQ,CAAC;AAC9C,QAAM,mBAAmB,MAAM,WAAW,mBACtC,IACA,MAAM,WAAW,cACf,MACA;AAEN,QAAM,gBAAiB,kBAAkB,QAAQ,gBAAkB,kBAAkB,QAAQ;AAC7F,QAAM,cAAc,gBAAgB,QAAQ;AAC5C,QAAM,aAAa,eAAe,QAAQ;AAC1C,QAAM,aAAa,cAAc,QAAQ;AACzC,QAAM,iBAAiB,iBAAiB,oBAAoB,QAAQ;AACpE,QAAM,iBACH,gBAAgB,QAAQ,oBAAsB,gBAAgB,QAAQ;AACzE,QAAM,mBAAmB,iBAAiB,QAAQ;AAElD,QAAM,kBAAkB,KAAK,SAAS,SAAS;AAC/C,QAAM,aAAa,KAAK,SAAS,UAAU,KAAM,KAAK,SAAS,KAAK,KAAK,KAAK,SAAS,MAAM;AAC7F,QAAM,iBAAiB,KAAK,SAAS,KAAK,MAAM,KAAK,SAAS,UAAU,KAAK,KAAK,SAAS,MAAM;AACjG,QAAM,eAAe,KAAK,SAAS,aAAa,KAAK,KAAK,SAAS,WAAW;AAE9E,QAAM,cAAc,kBAAkB,IAAI,MAAM,aAAa,IAAI,MAAM,iBAAiB,IAAI,MAAM,eAAe,IAAI;AAErH,QAAM,QAAQ;AAAA,IACZ,gBAAgB,cAAc,aAAa,aAAa,gBAAgB,iBAAiB,aAAa;AAAA,EACxG;AAEA,MAAI,gBAAiB,SAAQ,KAAK,EAAE,MAAM,sBAAsB,CAAC;AACjE,MAAI,WAAY,SAAQ,KAAK,EAAE,MAAM,eAAe,CAAC;AACrD,MAAI,eAAgB,SAAQ,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC7D,MAAI,aAAc,SAAQ,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAE7D,MAAI,kBAAkB,EAAG,SAAQ,KAAK,EAAE,MAAM,mBAAmB,QAAQ,OAAO,eAAe,EAAE,CAAC;AAClG,MAAI,kBAAkB,EAAG,SAAQ,KAAK,EAAE,MAAM,qBAAqB,QAAQ,OAAO,eAAe,EAAE,CAAC;AACpG,MAAI,gBAAgB,EAAG,SAAQ,KAAK,EAAE,MAAM,gBAAgB,QAAQ,OAAO,aAAa,EAAE,CAAC;AAC3F,MAAI,eAAe,EAAG,SAAQ,KAAK,EAAE,MAAM,eAAe,QAAQ,OAAO,YAAY,EAAE,CAAC;AACxF,MAAI,cAAc,EAAG,SAAQ,KAAK,EAAE,MAAM,cAAc,CAAC;AACzD,MAAI,iBAAiB,EAAG,SAAQ,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAChE,MAAI,gBAAgB,EAAG,SAAQ,KAAK,EAAE,MAAM,iBAAiB,QAAQ,OAAO,aAAa,EAAE,CAAC;AAC5F,MAAI,gBAAgB,EAAG,SAAQ,KAAK,EAAE,MAAM,iBAAiB,QAAQ,OAAO,aAAa,EAAE,CAAC;AAC5F,MAAI,iBAAiB,EAAG,SAAQ,KAAK,EAAE,MAAM,iBAAiB,QAAQ,OAAO,cAAc,EAAE,CAAC;AAE9F,MAAI,kBAAkB,EAAG,WAAU,KAAK,8CAA8C;AACtF,MAAI,iBAAiB,EAAG,WAAU,KAAK,qCAAqC;AAC5E,MAAI,MAAM,QAAQ,GAAI,WAAU,KAAK,2CAA2C;AAChF,MAAI,aAAc,WAAU,KAAK,sCAAsC;AAEvE,QAAM,SAAoC;AAAA,IACxC;AAAA,IACA,OAAO;AAAA,IACP;AAAA,IACA;AAAA,IACA,UAAU,iBAAiB;AAAA,EAC7B;AAEA,MAAI,QAAQ,gBAAgB;AAC1B,WAAO,YAAY;AAAA,MACjB,UAAU,WAAW,aAAa;AAAA,MAClC,QAAQ,WAAW,WAAW;AAAA,MAC9B,OAAO,WAAW,UAAU;AAAA,MAC5B,OAAO,WAAW,UAAU;AAAA,MAC5B,UAAU,WAAW,aAAa;AAAA,MAClC,WAAW,WAAW,cAAc;AAAA,MACpC,kBAAkB,WAAW,gBAAgB;AAAA,MAC7C;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AA+BO,SAAS,gBACd,QACA,eACA,UAAiC,CAAC,GACX;AACvB,QAAM,aAAa,+BAA+B,aAAa;AAC/D,MAAI,CAAC,WAAW,OAAO;AACrB,UAAM,QAAQ,WAAW,OAAO,CAAC;AACjC,UAAM,QAAQ,IAAI,MAAM,OAAO,WAAW,iCAAiC;AAI3E,UAAM,OAAO,OAAO;AACpB,UAAM,SAAS,WAAW;AAC1B,UAAM;AAAA,EACR;AAEA,QAAM,WAAW,gCAAgC,aAAa;AAC9D,QAAM,UAAU,OACb,IAAI,CAAC,UAAU,yBAAyB,OAAO,UAAU,OAAO,CAAC,EACjE,KAAK,CAAC,GAAG,MAAM;AACd,QAAI,EAAE,UAAU,EAAE,MAAO,QAAO,EAAE,QAAQ,EAAE;AAC5C,QAAI,EAAE,MAAM,UAAU,EAAE,MAAM,MAAO,QAAO,EAAE,MAAM,QAAQ,EAAE,MAAM;AACpE,WAAO,EAAE,MAAM,WAAW,cAAc,EAAE,MAAM,UAAU;AAAA,EAC5D,CAAC;AAEH,SAAO;AAAA,IACL;AAAA,IACA,SAAS,OAAO,QAAQ,QAAQ,WAAW,QAAQ,MAAM,GAAG,KAAK,IAAI,GAAG,QAAQ,GAAG,CAAC,IAAI;AAAA,EAC1F;AACF;AAWO,IAAM,aAAa;;;AChmBnB,SAAS,2BACd,QACA,MACkC;AAClC,QAAM,MAAM,OAAO;AAEnB,MAAI,KAAK,SAAS,SAAS;AACzB,QAAI,IAAI,WAAW,EAAG,QAAO;AAC7B,UAAM,QAAkB,CAAC,uBAAuB,EAAE;AAClD,eAAW,CAAC,OAAO,KAAK,KAAK,IAAI,QAAQ,GAAG;AAC1C,YAAM,SAAS,UAAU,IAAI,mBAAmB;AAChD,YAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,MAAM,MAAM,UAAU,GAAG,MAAM,EAAE;AAC7D,YAAM,KAAK,WAAW,MAAM,QAAQ,IAAI,CAAC,WAAW,OAAO,IAAI,EAAE,KAAK,IAAI,KAAK,mBAAmB,EAAE;AACpG,YAAM,KAAK,gBAAgB,MAAM,UAAU,CAAC,KAAK,MAAM,EAAE;AAAA,IAC3D;AACA,UAAM,KAAK,EAAE;AACb,UAAM,KAAK,WAAW,IAAI,IAAI,CAAC,GAAG,UAAU,QAAQ,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE;AAClE,WAAO,MAAM,KAAK,IAAI;AAAA,EACxB;AAEA,QAAM,UAAU,IAAI,IAAI,CAAC,OAAO,WAAW;AAAA,IACzC,MAAM,QAAQ;AAAA,IACd,YAAY,MAAM,MAAM;AAAA,IACxB,OAAO,MAAM;AAAA,IACb,SAAS,MAAM;AAAA,IACf,WAAW,MAAM;AAAA,IACjB,GAAI,KAAK,UACL;AAAA,MACE,aAAa,MAAM,MAAM;AAAA,MACzB,QAAQ,MAAM,MAAM;AAAA,MACpB,UAAU,MAAM,aAAa;AAAA,IAC/B,IACA,CAAC;AAAA,EACP,EAAE;AAEF,SAAO;AAAA,IACL,OAAO,OAAO,SAAS;AAAA,IACvB,aAAa,QAAQ,CAAC,KAAK;AAAA,IAC3B;AAAA,EACF;AACF;AAqBA,eAAsB,aAAa,OAAe,UAA+B,CAAC,GAAG;AACnF,QAAM,UAAU,MAAM,KAAK;AAC3B,MAAI,CAAC,SAAS;AACZ,UAAM,QAAQ,IAAI,MAAM,yBAAyB;AACjD,UAAM,OAAO,2BAA2B;AACxC,UAAM;AAAA,EACR;AAEA,QAAM,SAAS,IAAI,kBAAkB;AACrC,MAAI;AACF,WAAO,MAAM,OAAO,OAAO,SAAS,QAAQ,SAAS,EAAE;AAAA,EACzD,SAAS,OAAO;AACd,UAAM,UAAU,IAAI,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAChF,YAAQ,OAAO,2BAA2B;AAC1C,UAAM;AAAA,EACR;AACF;AAuBA,eAAsBC,iBACpB,OACA,UACA,UAAuC,CAAC,GACR;AAChC,QAAM,OAAO,MAAM,aAAa,OAAO,EAAE,OAAO,QAAQ,SAAS,KAAK,KAAK,QAAQ,OAAO,KAAK,GAAG,EAAE,EAAE,CAAC;AACvG,QAAM,SAAS,gBAAW,MAAM,EAAE,GAAG,UAAU,MAAM,GAAG,OAAO;AAE/D,MAAI,OAAO,QAAQ,WAAW,GAAG;AAC/B,UAAM,QAAQ,IAAI,MAAM,kBAAkB;AAC1C,UAAM,OAAO,2BAA2B;AACxC,UAAM;AAAA,EACR;AAEA,SAAO;AACT;;;AC7JA,SAAS,cAAAC,oBAAkB;AAC3B,SAAS,YAAAC,iBAAgB;;;ACCzB,SAAS,KACP,IACA,MACA,aACA,UACA,UACA,SACW;AACX,SAAO,EAAE,IAAI,MAAM,aAAa,UAAU,UAAU,QAAQ;AAC9D;AAYO,IAAM,cAA2B;AAAA;AAAA,EAEtC;AAAA,IAAK;AAAA,IAAS;AAAA,IAA0B;AAAA,IAA4C;AAAA,IAAY;AAAA,IAC9F;AAAA,EAA4G;AAAA,EAC9G;AAAA,IAAK;AAAA,IAAS;AAAA,IAAqB;AAAA,IAAuC;AAAA,IAAY;AAAA,IACpF;AAAA,EAAmF;AAAA,EACrF;AAAA,IAAK;AAAA,IAAS;AAAA,IAAqB;AAAA,IAA6B;AAAA,IAAY;AAAA,IAC1E;AAAA,EAA8E;AAAA,EAChF;AAAA,IAAK;AAAA,IAAS;AAAA,IAAwB;AAAA,IAAuC;AAAA,IAAQ;AAAA,IACnF;AAAA,EAA+E;AAAA,EACjF;AAAA,IAAK;AAAA,IAAS;AAAA,IAAuB;AAAA,IAAiD;AAAA,IAAQ;AAAA,IAC5F;AAAA,EAAyD;AAAA,EAC3D;AAAA,IAAK;AAAA,IAAS;AAAA,IAAmB;AAAA,IAA6B;AAAA,IAAU;AAAA,IACtE;AAAA,EAA+C;AAAA,EACjD;AAAA,IAAK;AAAA,IAAS;AAAA,IAAwB;AAAA,IAA6B;AAAA,IAAQ;AAAA,IACzE;AAAA,EAA+D;AAAA,EACjE;AAAA,IAAK;AAAA,IAAS;AAAA,IAAmB;AAAA,IAA6C;AAAA,IAAU;AAAA,IACtF;AAAA,EAAwC;AAAA;AAAA,EAG1C;AAAA,IAAK;AAAA,IAAS;AAAA,IAAuB;AAAA,IAAwC;AAAA,IAAY;AAAA,IACvF;AAAA,EAAmE;AAAA,EACrE;AAAA,IAAK;AAAA,IAAS;AAAA,IAAyB;AAAA,IAAyC;AAAA,IAAY;AAAA,IAC1F;AAAA,EAAgE;AAAA,EAClE;AAAA,IAAK;AAAA,IAAS;AAAA,IAAc;AAAA,IAA0B;AAAA,IAAQ;AAAA,IAC5D;AAAA,EAAa;AAAA,EACf;AAAA,IAAK;AAAA,IAAS;AAAA,IAAe;AAAA,IAA4B;AAAA,IAAQ;AAAA,IAC/D;AAAA,EAA0C;AAAA,EAC5C;AAAA,IAAK;AAAA,IAAS;AAAA,IAAmB;AAAA,IAAiC;AAAA,IAAY;AAAA,IAC5E;AAAA,EAAiD;AAAA,EACnD;AAAA,IAAK;AAAA,IAAS;AAAA,IAA4B;AAAA,IAAuC;AAAA,IAAQ;AAAA,IACvF;AAAA,EAA0C;AAAA,EAC5C;AAAA,IAAK;AAAA,IAAS;AAAA,IAAuB;AAAA,IAA8B;AAAA,IAAQ;AAAA,IACzE;AAAA,EAAgD;AAAA,EAClD;AAAA,IAAK;AAAA,IAAS;AAAA,IAAoB;AAAA,IAA6B;AAAA,IAAQ;AAAA,IACrE;AAAA,EAAmE;AAAA;AAAA,EAGrE;AAAA,IAAK;AAAA,IAAS;AAAA,IAAqB;AAAA,IAA4B;AAAA,IAAY;AAAA,IACzE;AAAA,EAAqF;AAAA,EACvF;AAAA,IAAK;AAAA,IAAS;AAAA,IAAsB;AAAA,IAAmC;AAAA,IAAY;AAAA,IACjF;AAAA,EAAyE;AAAA,EAC3E;AAAA,IAAK;AAAA,IAAS;AAAA,IAAe;AAAA,IAAuC;AAAA,IAAQ;AAAA,IAC1E;AAAA,EAA6F;AAAA,EAC/F;AAAA,IAAK;AAAA,IAAS;AAAA,IAAsB;AAAA,IAAyC;AAAA,IAAY;AAAA,IACvF;AAAA,EAAoF;AAAA,EACtF;AAAA,IAAK;AAAA,IAAS;AAAA,IAAwB;AAAA,IAA6B;AAAA,IAAQ;AAAA,IACzE;AAAA,EAAkE;AAAA,EACpE;AAAA,IAAK;AAAA,IAAS;AAAA,IAAmB;AAAA,IAA6B;AAAA,IAAY;AAAA,IACxE;AAAA,EAAuF;AAAA;AAAA,EAGzF;AAAA,IAAK;AAAA,IAAS;AAAA,IAAmB;AAAA,IAAsC;AAAA,IAAQ;AAAA,IAC7E;AAAA,EAAwC;AAAA,EAC1C;AAAA,IAAK;AAAA,IAAS;AAAA,IAAa;AAAA,IAA6B;AAAA,IAAY;AAAA,IAClE;AAAA,EAAkB;AAAA,EACpB;AAAA,IAAK;AAAA,IAAS;AAAA,IAAiB;AAAA,IAA6B;AAAA,IAAY;AAAA,IACtE;AAAA,EAA4D;AAAA,EAC9D;AAAA,IAAK;AAAA,IAAS;AAAA,IAAiB;AAAA,IAA0B;AAAA,IAAY;AAAA,IACnE;AAAA,EAA+B;AAAA;AAAA,EAGjC;AAAA,IAAK;AAAA,IAAS;AAAA,IAA0B;AAAA,IAAiC;AAAA,IAAY;AAAA,IACnF;AAAA,EAAuE;AAAA,EACzE;AAAA,IAAK;AAAA,IAAS;AAAA,IAAwB;AAAA,IAAyB;AAAA,IAAU;AAAA,IACvE;AAAA,EAAoC;AAAA,EACtC;AAAA,IAAK;AAAA,IAAS;AAAA,IAAkB;AAAA,IAAwC;AAAA,IAAQ;AAAA,IAC9E;AAAA,EAAuD;AAAA,EACzD;AAAA,IAAK;AAAA,IAAS;AAAA,IAAuB;AAAA,IAAuC;AAAA,IAAU;AAAA,IACpF;AAAA,EAA0D;AAAA;AAAA,EAG5D;AAAA,IAAK;AAAA,IAAS;AAAA,IAAoB;AAAA,IAA6B;AAAA,IAAQ;AAAA,IACrE;AAAA,EAAyC;AAAA,EAC3C;AAAA,IAAK;AAAA,IAAS;AAAA,IAAiB;AAAA,IAA0B;AAAA,IAAY;AAAA,IACnE;AAAA,EAA8C;AAAA,EAChD;AAAA,IAAK;AAAA,IAAS;AAAA,IAAiB;AAAA,IAAoB;AAAA,IAAU;AAAA,IAC3D;AAAA,EAA2B;AAAA,EAC7B;AAAA,IAAK;AAAA,IAAS;AAAA,IAAgB;AAAA,IAA4B;AAAA,IAAQ;AAAA,IAChE;AAAA,EAAsC;AAAA;AAAA,EAGxC;AAAA,IAAK;AAAA,IAAS;AAAA,IAAgB;AAAA,IAAwB;AAAA,IAAU;AAAA,IAC9D;AAAA,EAA4C;AAAA,EAC9C;AAAA,IAAK;AAAA,IAAS;AAAA,IAAwB;AAAA,IAAuC;AAAA,IAAU;AAAA,IACrF;AAAA,EAA8D;AAAA,EAChE;AAAA,IAAK;AAAA,IAAS;AAAA,IAAkB;AAAA,IAA4B;AAAA,IAAU;AAAA,IACpE;AAAA,EAA4C;AAAA;AAAA,EAG9C;AAAA,IAAK;AAAA,IAAS;AAAA,IAAmB;AAAA,IAAkC;AAAA,IAAU;AAAA,IAC3E;AAAA,EAAuE;AAAA,EACzE;AAAA,IAAK;AAAA,IAAS;AAAA,IAA0B;AAAA,IAAkC;AAAA,IAAO;AAAA,IAC/E;AAAA,EAAgF;AAAA,EAClF;AAAA,IAAK;AAAA,IAAS;AAAA,IAAsB;AAAA,IAAyB;AAAA,IAAU;AAAA,IACrE;AAAA,EAA+D;AAAA,EACjE;AAAA,IAAK;AAAA,IAAS;AAAA,IAAqB;AAAA,IAA6B;AAAA,IAAQ;AAAA,IACtE;AAAA,EAAmE;AAAA;AAAA,EAGrE;AAAA,IAAK;AAAA,IAAS;AAAA,IAAmB;AAAA,IAA6B;AAAA,IAAO;AAAA,IACnE;AAAA,EAAiC;AAAA,EACnC;AAAA,IAAK;AAAA,IAAS;AAAA,IAAsB;AAAA,IAAgC;AAAA,IAAO;AAAA,IACzE;AAAA,EAAwC;AAAA,EAC1C;AAAA,IAAK;AAAA,IAAS;AAAA,IAAuB;AAAA,IAAiC;AAAA,IAAO;AAAA,IAC3E;AAAA,EAAkD;AACtD;;;AD5HA,IAAM,mBAAkD;AAAA,EACtD,UAAU;AAAA,EACV,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,KAAK;AAAA,EACL,MAAM;AACR;AAsBA,eAAsB,SACpB,UACA,OACsB;AACtB,MAAI,CAACC,aAAW,QAAQ,GAAG;AACzB,WAAO,EAAE,MAAM,UAAU,UAAU,CAAC,GAAG,OAAO,KAAK,QAAQ,KAAK;AAAA,EAClE;AAEA,QAAM,UAAU,MAAMC,UAAS,UAAU,OAAO;AAChD,QAAM,QAAQ,QAAQ,MAAM,IAAI;AAChC,QAAM,cAAc,SAAS;AAC7B,QAAM,WAA2B,CAAC;AAElC,aAAWC,SAAQ,aAAa;AAC9B,aAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,YAAM,OAAO,MAAM,CAAC,KAAK;AACzB,YAAM,QAAQ,KAAK,MAAMA,MAAK,OAAO;AACrC,UAAI,OAAO;AACT,iBAAS,KAAK;AAAA,UACZ,MAAAA;AAAA,UACA,MAAM,IAAI;AAAA,UACV,SAAS,MAAM,SAAS,KAAK;AAAA,UAC7B,OAAO,MAAM,CAAC;AAAA,UACd,SAAS,KAAK,KAAK;AAAA,QACrB,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAGA,QAAM,eAAe,SAAS;AAAA,IAC5B,CAAC,KAAK,MAAM,OAAO,iBAAiB,EAAE,KAAK,QAAQ,KAAK;AAAA,IACxD;AAAA,EACF;AACA,QAAM,QAAQ,KAAK,IAAI,GAAG,MAAM,YAAY;AAC5C,QAAM,SAAS,CAAC,SAAS,KAAK,CAAC,MAAM,EAAE,KAAK,aAAa,cAAc,EAAE,KAAK,aAAa,MAAM;AAEjG,SAAO,EAAE,MAAM,UAAU,UAAU,OAAO,OAAO;AACnD;AAqBA,eAAsB,cAAc,SAAyC;AAC3E,QAAM,EAAE,SAAAC,SAAQ,IAAI,MAAM,OAAO,aAAkB;AACnD,QAAM,EAAE,MAAAC,MAAK,IAAI,MAAM,OAAO,MAAW;AAEzC,MAAI,CAACJ,aAAW,OAAO,EAAG,QAAO,CAAC;AAElC,QAAM,UAAU,MAAMG,SAAQ,SAAS,EAAE,eAAe,KAAK,CAAC;AAC9D,QAAM,UAAyB,CAAC;AAEhC,aAAW,SAAS,SAAS;AAC3B,QAAI,MAAM,YAAY,KAAK,MAAM,eAAe,GAAG;AACjD,YAAM,YAAYC,MAAK,SAAS,MAAM,MAAM,UAAU;AACtD,UAAIJ,aAAW,SAAS,GAAG;AACzB,gBAAQ,KAAK,MAAM,SAAS,SAAS,CAAC;AAAA,MACxC;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAqBO,SAAS,QAAQ,SAAgC;AACtD,SAAO;AAAA,IACL,SAAS;AAAA,IACT,SAAS;AAAA,IACT,MAAM;AAAA,MACJ;AAAA,QACE,MAAM;AAAA,UACJ,QAAQ;AAAA,YACN,MAAM;AAAA,YACN,SAAS;AAAA,YACT,OAAO,YAAY,IAAI,CAAC,OAAO;AAAA,cAC7B,IAAI,EAAE;AAAA,cACN,MAAM,EAAE;AAAA,cACR,kBAAkB,EAAE,MAAM,EAAE,YAAY;AAAA,cACxC,sBAAsB;AAAA,gBACpB,OAAO,EAAE,aAAa,cAAc,EAAE,aAAa,SAAS,UAAU;AAAA,cACxE;AAAA,cACA,YAAY,EAAE,UAAU,EAAE,SAAS;AAAA,YACrC,EAAE;AAAA,UACJ;AAAA,QACF;AAAA,QACA,SAAS,QAAQ;AAAA,UAAQ,CAAC,WACxB,OAAO,SAAS,IAAI,CAAC,OAAO;AAAA,YAC1B,QAAQ,EAAE,KAAK;AAAA,YACf,OAAO,EAAE,KAAK,aAAa,cAAc,EAAE,KAAK,aAAa,SAAS,UAAU;AAAA,YAChF,SAAS,EAAE,MAAM,GAAG,EAAE,KAAK,WAAW,KAAK,EAAE,KAAK,GAAG;AAAA,YACrD,WAAW;AAAA,cACT;AAAA,gBACE,kBAAkB;AAAA,kBAChB,kBAAkB,EAAE,KAAK,OAAO,KAAK;AAAA,kBACrC,QAAQ;AAAA,oBACN,WAAW,EAAE;AAAA,oBACb,aAAa,EAAE;AAAA,kBACjB;AAAA,gBACF;AAAA,cACF;AAAA,YACF;AAAA,UACF,EAAE;AAAA,QACJ;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;;;AE/KA,SAAS,YAAAK,iBAAgB;AACzB,SAAS,cAAAC,oBAAkB;AAC3B,OAAOC,aAAY;AAiDnB,IAAM,iBAAiB;AAAA,EACrB;AAAA,EAAa;AAAA,EAAU;AAAA,EAAU;AAAA,EAAU;AAAA,EAC3C;AAAA,EAAU;AAAA,EAAY;AAAA,EAAS;AAAA,EAAU;AAC3C;AAEA,IAAM,eAAe;AACrB,IAAM,kBAAkB;AACxB,IAAM,yBAAyB;AAC/B,IAAM,kBAAkB;AACxB,IAAM,0BAA0B;AAqBhC,eAAsB,cAAc,UAA6C;AAC/E,QAAM,SAA4B,CAAC;AAEnC,MAAI,CAACD,aAAW,QAAQ,GAAG;AACzB,WAAO;AAAA,MACL,OAAO;AAAA,MACP,QAAQ,CAAC,EAAE,OAAO,SAAS,OAAO,QAAQ,SAAS,sBAAsB,CAAC;AAAA,MAC1E,UAAU;AAAA,IACZ;AAAA,EACF;AAEA,QAAM,UAAU,MAAMD,UAAS,UAAU,OAAO;AAGhD,MAAI,CAAC,QAAQ,WAAW,KAAK,GAAG;AAC9B,WAAO,KAAK;AAAA,MACV,OAAO;AAAA,MACP,OAAO;AAAA,MACP,SAAS;AAAA,IACX,CAAC;AACD,WAAO,EAAE,OAAO,OAAO,QAAQ,UAAU,KAAK;AAAA,EAChD;AAEA,MAAI;AACJ,MAAI;AAEJ,MAAI;AACF,UAAM,SAASE,QAAO,OAAO;AAC7B,WAAO,OAAO;AACd,WAAO,OAAO;AAAA,EAChB,SAAS,KAAK;AACZ,WAAO,KAAK;AAAA,MACV,OAAO;AAAA,MACP,OAAO;AAAA,MACP,SAAS,6BAA6B,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,IACxF,CAAC;AACD,WAAO,EAAE,OAAO,OAAO,QAAQ,UAAU,KAAK;AAAA,EAChD;AAGA,MAAI,CAAC,KAAK,MAAM;AACd,WAAO,KAAK,EAAE,OAAO,SAAS,OAAO,QAAQ,SAAS,+BAA+B,CAAC;AAAA,EACxF,OAAO;AACL,UAAM,OAAO,OAAO,KAAK,IAAI;AAE7B,QAAI,KAAK,SAAS,iBAAiB;AACjC,aAAO,KAAK;AAAA,QACV,OAAO;AAAA,QACP,OAAO;AAAA,QACP,SAAS,kBAAkB,KAAK,MAAM,eAAe,eAAe;AAAA,MACtE,CAAC;AAAA,IACH;AAEA,QAAI,CAAC,aAAa,KAAK,IAAI,GAAG;AAC5B,aAAO,KAAK;AAAA,QACV,OAAO;AAAA,QACP,OAAO;AAAA,QACP,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AAEA,QAAI,eAAe,SAAS,KAAK,YAAY,CAAC,GAAG;AAC/C,aAAO,KAAK;AAAA,QACV,OAAO;AAAA,QACP,OAAO;AAAA,QACP,SAAS,SAAS,IAAI;AAAA,MACxB,CAAC;AAAA,IACH;AAEA,QAAI,UAAU,KAAK,IAAI,GAAG;AACxB,aAAO,KAAK;AAAA,QACV,OAAO;AAAA,QACP,OAAO;AAAA,QACP,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AAAA,EACF;AAGA,MAAI,CAAC,KAAK,aAAa;AACrB,WAAO,KAAK,EAAE,OAAO,SAAS,OAAO,eAAe,SAAS,sCAAsC,CAAC;AAAA,EACtG,OAAO;AACL,UAAM,OAAO,OAAO,KAAK,WAAW;AAEpC,QAAI,KAAK,SAAS,wBAAwB;AACxC,aAAO,KAAK;AAAA,QACV,OAAO;AAAA,QACP,OAAO;AAAA,QACP,SAAS,yBAAyB,KAAK,MAAM,eAAe,sBAAsB;AAAA,MACpF,CAAC;AAAA,IACH;AAEA,QAAI,KAAK,SAAS,yBAAyB;AACzC,aAAO,KAAK;AAAA,QACV,OAAO;AAAA,QACP,OAAO;AAAA,QACP,SAAS,yBAAyB,KAAK,MAAM;AAAA,MAC/C,CAAC;AAAA,IACH;AAEA,QAAI,UAAU,KAAK,IAAI,GAAG;AACxB,aAAO,KAAK;AAAA,QACV,OAAO;AAAA,QACP,OAAO;AAAA,QACP,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AAAA,EACF;AAGA,QAAM,YAAY,KAAK,KAAK,EAAE,MAAM,IAAI,EAAE;AAC1C,MAAI,YAAY,iBAAiB;AAC/B,WAAO,KAAK;AAAA,MACV,OAAO;AAAA,MACP,OAAO;AAAA,MACP,SAAS,iBAAiB,SAAS;AAAA,IACrC,CAAC;AAAA,EACH;AAEA,MAAI,CAAC,KAAK,KAAK,GAAG;AAChB,WAAO,KAAK;AAAA,MACV,OAAO;AAAA,MACP,OAAO;AAAA,MACP,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAEA,QAAM,YAAY,OAAO,KAAK,CAAC,MAAM,EAAE,UAAU,OAAO;AAExD,SAAO;AAAA,IACL,OAAO,CAAC;AAAA,IACR;AAAA,IACA,UAAU;AAAA,EACZ;AACF;","names":["mkdir","dirname","existsSync","readFile","writeFile","existsSync","readFile","writeFile","existsSync","readFile","writeFile","existsSync","readFile","writeFile","existsSync","existsSync","existsSync","existsSync","existsSync","join","join","existsSync","stat","readdir","existsSync","lstatSync","cp","mkdir","readFile","rm","symlink","writeFile","join","join","existsSync","readFile","rm","mkdir","writeFile","cp","stat","lstatSync","symlink","execFileSync","existsSync","resolve","readFile","writeFile","mkdir","rm","existsSync","resolve","rm","mkdir","writeFile","existsSync","readFile","existing","API_BASE","toResult","existsSync","basename","dirname","join","require","getSkillDir","existsSync","join","join","existsSync","readFile","existsSync","join","currentVersion","hasUpdate","recommendSkills","existsSync","readFile","existsSync","readFile","rule","readdir","join","readFile","existsSync","matter"]}
|