@cleocode/caamp 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/core/registry/providers.ts","../src/core/logger.ts","../src/core/registry/detection.ts","../src/core/sources/parser.ts","../src/core/skills/installer.ts","../src/core/lock-utils.ts","../src/core/skills/lock.ts","../src/core/marketplace/skillsmp.ts","../src/core/marketplace/skillssh.ts","../src/core/marketplace/client.ts","../src/core/skills/discovery.ts","../src/core/skills/audit/scanner.ts","../src/core/skills/audit/rules.ts","../src/core/skills/validator.ts","../src/core/formats/utils.ts","../src/core/formats/json.ts","../src/core/formats/yaml.ts","../src/core/formats/toml.ts","../src/core/formats/index.ts","../src/core/mcp/transforms.ts","../src/core/mcp/reader.ts","../src/core/mcp/installer.ts","../src/core/mcp/lock.ts","../src/core/instructions/injector.ts","../src/core/instructions/templates.ts"],"sourcesContent":["/**\n * Provider registry loader\n *\n * Loads providers from providers/registry.json and resolves\n * platform-specific paths at runtime.\n */\n\nimport { readFileSync, existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join, dirname } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { Provider, ConfigFormat, TransportType, ProviderPriority, ProviderStatus, DetectionMethod } from \"../../types.js\";\nimport type { ProviderRegistry, RegistryProvider } from \"./types.js\";\n\nfunction findRegistryPath(): string {\n const thisDir = dirname(fileURLToPath(import.meta.url));\n\n // Development: src/core/registry/ -> ../../.. -> providers/registry.json\n const devPath = join(thisDir, \"..\", \"..\", \"..\", \"providers\", \"registry.json\");\n if (existsSync(devPath)) return devPath;\n\n // Bundled: dist/ -> .. -> providers/registry.json\n const distPath = join(thisDir, \"..\", \"providers\", \"registry.json\");\n if (existsSync(distPath)) return distPath;\n\n // Fallback: traverse up until we find it\n let dir = thisDir;\n for (let i = 0; i < 5; i++) {\n const candidate = join(dir, \"providers\", \"registry.json\");\n if (existsSync(candidate)) return candidate;\n dir = dirname(dir);\n }\n\n throw new Error(`Cannot find providers/registry.json (searched from ${thisDir})`);\n}\n\nlet _registry: ProviderRegistry | null = null;\nlet _providers: Map<string, Provider> | null = null;\nlet _aliasMap: Map<string, string> | null = null;\n\nfunction getPlatformPaths(): {\n config: string;\n vscodeConfig: string;\n zedConfig: string;\n claudeDesktopConfig: string;\n} {\n const home = homedir();\n const platform = process.platform;\n\n if (platform === \"win32\") {\n const appData = process.env[\"APPDATA\"] ?? join(home, \"AppData\", \"Roaming\");\n return {\n config: appData,\n vscodeConfig: join(appData, \"Code\", \"User\"),\n zedConfig: join(appData, \"Zed\"),\n claudeDesktopConfig: join(appData, \"Claude\"),\n };\n } else if (platform === \"darwin\") {\n return {\n config: process.env[\"XDG_CONFIG_HOME\"] ?? join(home, \".config\"),\n vscodeConfig: join(home, \"Library\", \"Application Support\", \"Code\", \"User\"),\n zedConfig: join(home, \"Library\", \"Application Support\", \"Zed\"),\n claudeDesktopConfig: join(home, \"Library\", \"Application Support\", \"Claude\"),\n };\n } else {\n const config = process.env[\"XDG_CONFIG_HOME\"] ?? join(home, \".config\");\n return {\n config,\n vscodeConfig: join(config, \"Code\", \"User\"),\n zedConfig: join(config, \"zed\"),\n claudeDesktopConfig: join(config, \"Claude\"),\n };\n }\n}\n\nfunction resolvePath(template: string): string {\n const home = homedir();\n const paths = getPlatformPaths();\n\n return template\n .replace(/\\$HOME/g, home)\n .replace(/\\$CONFIG/g, paths.config)\n .replace(/\\$VSCODE_CONFIG/g, paths.vscodeConfig)\n .replace(/\\$ZED_CONFIG/g, paths.zedConfig)\n .replace(/\\$CLAUDE_DESKTOP_CONFIG/g, paths.claudeDesktopConfig);\n}\n\nfunction resolveProvider(raw: RegistryProvider): Provider {\n return {\n id: raw.id,\n toolName: raw.toolName,\n vendor: raw.vendor,\n agentFlag: raw.agentFlag,\n aliases: raw.aliases,\n pathGlobal: resolvePath(raw.pathGlobal),\n pathProject: raw.pathProject,\n instructFile: raw.instructFile,\n configKey: raw.configKey,\n configFormat: raw.configFormat as ConfigFormat,\n configPathGlobal: resolvePath(raw.configPathGlobal),\n configPathProject: raw.configPathProject,\n pathSkills: resolvePath(raw.pathSkills),\n pathProjectSkills: raw.pathProjectSkills,\n detection: {\n methods: raw.detection.methods as DetectionMethod[],\n binary: raw.detection.binary,\n directories: raw.detection.directories?.map(resolvePath),\n appBundle: raw.detection.appBundle,\n flatpakId: raw.detection.flatpakId,\n },\n supportedTransports: raw.supportedTransports as TransportType[],\n supportsHeaders: raw.supportsHeaders,\n priority: raw.priority as ProviderPriority,\n status: raw.status as ProviderStatus,\n agentSkillsCompatible: raw.agentSkillsCompatible,\n };\n}\n\nfunction loadRegistry(): ProviderRegistry {\n if (_registry) return _registry;\n\n const registryPath = findRegistryPath();\n const raw = readFileSync(registryPath, \"utf-8\");\n _registry = JSON.parse(raw) as ProviderRegistry;\n return _registry;\n}\n\nfunction ensureProviders(): void {\n if (_providers) return;\n\n const registry = loadRegistry();\n _providers = new Map<string, Provider>();\n _aliasMap = new Map<string, string>();\n\n for (const [id, raw] of Object.entries(registry.providers)) {\n const provider = resolveProvider(raw);\n _providers.set(id, provider);\n\n // Build alias map\n for (const alias of provider.aliases) {\n _aliasMap.set(alias, id);\n }\n }\n}\n\n/**\n * Retrieve all registered providers with resolved platform paths.\n *\n * Providers are lazily loaded from `providers/registry.json` on first call\n * and cached for subsequent calls.\n *\n * @returns Array of all provider definitions\n *\n * @example\n * ```typescript\n * const providers = getAllProviders();\n * console.log(`${providers.length} providers registered`);\n * ```\n */\nexport function getAllProviders(): Provider[] {\n ensureProviders();\n return Array.from(_providers!.values());\n}\n\n/**\n * Look up a provider by its ID or any of its aliases.\n *\n * @param idOrAlias - Provider ID (e.g. `\"claude-code\"`) or alias (e.g. `\"claude\"`)\n * @returns The matching provider, or `undefined` if not found\n *\n * @example\n * ```typescript\n * const provider = getProvider(\"claude\");\n * // Returns the claude-code provider via alias resolution\n * ```\n */\nexport function getProvider(idOrAlias: string): Provider | undefined {\n ensureProviders();\n const resolved = _aliasMap!.get(idOrAlias) ?? idOrAlias;\n return _providers!.get(resolved);\n}\n\n/**\n * Resolve an alias to its canonical provider ID.\n *\n * If the input is already a canonical ID (or unrecognized), it is returned as-is.\n *\n * @param idOrAlias - Provider ID or alias to resolve\n * @returns The canonical provider ID\n *\n * @example\n * ```typescript\n * resolveAlias(\"claude\"); // \"claude-code\"\n * resolveAlias(\"claude-code\"); // \"claude-code\"\n * resolveAlias(\"unknown\"); // \"unknown\"\n * ```\n */\nexport function resolveAlias(idOrAlias: string): string {\n ensureProviders();\n return _aliasMap!.get(idOrAlias) ?? idOrAlias;\n}\n\n/**\n * Filter providers by their priority tier.\n *\n * @param priority - Priority level to filter by (`\"high\"`, `\"medium\"`, or `\"low\"`)\n * @returns Array of providers matching the given priority\n *\n * @example\n * ```typescript\n * const highPriority = getProvidersByPriority(\"high\");\n * ```\n */\nexport function getProvidersByPriority(priority: ProviderPriority): Provider[] {\n return getAllProviders().filter((p) => p.priority === priority);\n}\n\n/**\n * Filter providers by their lifecycle status.\n *\n * @param status - Status to filter by (`\"active\"`, `\"beta\"`, `\"deprecated\"`, or `\"planned\"`)\n * @returns Array of providers matching the given status\n *\n * @example\n * ```typescript\n * const active = getProvidersByStatus(\"active\");\n * ```\n */\nexport function getProvidersByStatus(status: ProviderStatus): Provider[] {\n return getAllProviders().filter((p) => p.status === status);\n}\n\n/**\n * Filter providers that use a specific instruction file.\n *\n * Multiple providers often share the same instruction file (e.g. many use `\"AGENTS.md\"`).\n *\n * @param file - Instruction file name (e.g. `\"CLAUDE.md\"`, `\"AGENTS.md\"`)\n * @returns Array of providers that use the given instruction file\n *\n * @example\n * ```typescript\n * const claudeProviders = getProvidersByInstructFile(\"CLAUDE.md\");\n * ```\n */\nexport function getProvidersByInstructFile(file: string): Provider[] {\n return getAllProviders().filter((p) => p.instructFile === file);\n}\n\n/**\n * Get the set of all unique instruction file names across all providers.\n *\n * @returns Array of unique instruction file names (e.g. `[\"CLAUDE.md\", \"AGENTS.md\", \"GEMINI.md\"]`)\n *\n * @example\n * ```typescript\n * const files = getInstructionFiles();\n * // [\"CLAUDE.md\", \"AGENTS.md\", \"GEMINI.md\"]\n * ```\n */\nexport function getInstructionFiles(): string[] {\n const files = new Set<string>();\n for (const p of getAllProviders()) {\n files.add(p.instructFile);\n }\n return Array.from(files);\n}\n\n/**\n * Get the total number of registered providers.\n *\n * @returns Count of providers in the registry\n *\n * @example\n * ```typescript\n * console.log(`Registry has ${getProviderCount()} providers`);\n * ```\n */\nexport function getProviderCount(): number {\n ensureProviders();\n return _providers!.size;\n}\n\n/**\n * Get the semantic version string of the provider registry.\n *\n * @returns Version string from `providers/registry.json` (e.g. `\"1.0.0\"`)\n *\n * @example\n * ```typescript\n * console.log(`Registry version: ${getRegistryVersion()}`);\n * ```\n */\nexport function getRegistryVersion(): string {\n return loadRegistry().version;\n}\n\n/** Reset cached data (for testing) */\nexport function resetRegistry(): void {\n _registry = null;\n _providers = null;\n _aliasMap = null;\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;\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 * @example\n * ```typescript\n * setVerbose(true);\n * ```\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 * @example\n * ```typescript\n * setQuiet(true);\n * ```\n */\nexport function setQuiet(q: boolean): void {\n quietMode = q;\n}\n\nexport function debug(...args: unknown[]): void {\n if (verboseMode) console.error(\"[debug]\", ...args);\n}\n\nexport function info(...args: unknown[]): void {\n if (!quietMode) console.log(...args);\n}\n\nexport function warn(...args: unknown[]): void {\n if (!quietMode) console.warn(...args);\n}\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 * @returns `true` if verbose mode is active\n *\n * @example\n * ```typescript\n * if (isVerbose()) {\n * console.error(\"Extra debug info\");\n * }\n * ```\n */\nexport function isVerbose(): boolean {\n return verboseMode;\n}\n\n/**\n * Check if quiet mode is currently enabled.\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 */\nexport function isQuiet(): boolean {\n return quietMode;\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 { existsSync } from \"node:fs\";\nimport { execFileSync } from \"node:child_process\";\nimport { join } from \"node:path\";\nimport type { Provider } from \"../../types.js\";\nimport { getAllProviders } from \"./providers.js\";\nimport { debug } from \"../logger.js\";\n\n/**\n * Result of detecting whether a provider is installed on the system.\n *\n * @example\n * ```typescript\n * const result = detectProvider(provider);\n * if (result.installed) {\n * console.log(`Found via: ${result.methods.join(\", \")}`);\n * }\n * ```\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\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 return existsSync(join(\"/Applications\", 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 * @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 */\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\n/** Detect if a provider has project-level config in the given directory */\nexport function detectProjectProvider(provider: Provider, projectDir: string): boolean {\n if (!provider.pathProject) return false;\n return existsSync(join(projectDir, provider.pathProject));\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 * @returns Array of detection results for all providers\n *\n * @example\n * ```typescript\n * const results = detectAllProviders();\n * const installed = results.filter(r => r.installed);\n * console.log(`${installed.length} agents detected`);\n * ```\n */\nexport function detectAllProviders(): DetectionResult[] {\n const providers = getAllProviders();\n return providers.map(detectProvider);\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 * @returns Array of installed provider definitions\n *\n * @example\n * ```typescript\n * const installed = getInstalledProviders();\n * console.log(installed.map(p => p.toolName).join(\", \"));\n * ```\n */\nexport function getInstalledProviders(): Provider[] {\n return detectAllProviders()\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 * @param projectDir - Absolute path to the project directory to check\n * @returns Array of detection results with `projectDetected` populated\n *\n * @example\n * ```typescript\n * const results = detectProjectProviders(\"/home/user/my-project\");\n * for (const r of results) {\n * if (r.projectDetected) {\n * console.log(`${r.provider.toolName} has project config`);\n * }\n * }\n * ```\n */\nexport function detectProjectProviders(projectDir: string): DetectionResult[] {\n const results = detectAllProviders();\n return results.map((r) => ({\n ...r,\n projectDetected: detectProjectProvider(r.provider, projectDir),\n }));\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\\/([^/]+)(?:\\/(.+))?)?/;\nconst GITLAB_URL = /^https?:\\/\\/(?:www\\.)?gitlab\\.com\\/([^/]+)\\/([^/]+)(?:\\/-\\/tree\\/([^/]+)(?:\\/(.+))?)?/;\nconst HTTP_URL = /^https?:\\/\\//;\nconst NPM_SCOPED = /^@[a-zA-Z0-9_.-]+\\/[a-zA-Z0-9_.-]+$/;\nconst NPM_PACKAGE = /^[a-zA-Z0-9_.-]+$/;\n\n/** Infer a display name from a source */\nfunction inferName(source: string, type: SourceType): string {\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 brand = parts.length === 3 ? parts[parts.length - 2]! : parts[0]!;\n if (brand !== \"www\" && brand !== \"api\" && brand !== \"mcp\") {\n return brand;\n }\n // Fall back to second-level domain\n return parts[parts.length - 2] ?? parts[0]!;\n }\n return parts[0]!;\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 === \"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 * 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 */\nexport function parseSource(input: string): ParsedSource {\n // GitHub URL\n const ghUrlMatch = input.match(GITHUB_URL);\n if (ghUrlMatch) {\n return {\n type: \"github\",\n value: input,\n inferredName: ghUrlMatch[2]!,\n owner: ghUrlMatch[1],\n repo: ghUrlMatch[2],\n ref: ghUrlMatch[3],\n path: ghUrlMatch[4],\n };\n }\n\n // GitLab URL\n const glUrlMatch = input.match(GITLAB_URL);\n if (glUrlMatch) {\n return {\n type: \"gitlab\",\n value: input,\n inferredName: glUrlMatch[2]!,\n owner: glUrlMatch[1],\n repo: glUrlMatch[2],\n ref: glUrlMatch[3],\n path: glUrlMatch[4],\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 return {\n type: \"github\",\n value: `https://github.com/${ghShorthand[1]}/${ghShorthand[2]}`,\n inferredName: ghShorthand[2]!,\n owner: ghShorthand[1],\n repo: ghShorthand[2],\n path: ghShorthand[3],\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 * @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 */\nexport function isMarketplaceScoped(input: string): boolean {\n return /^@[a-zA-Z0-9_.-]+\\/[a-zA-Z0-9_.-]+$/.test(input);\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 { readFile, writeFile, mkdir, symlink, readlink, rm, cp } from \"node:fs/promises\";\nimport { existsSync, lstatSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join, relative, resolve } from \"node:path\";\nimport type { Provider, SkillMetadata, ParsedSource } from \"../../types.js\";\nimport { discoverSkill } from \"./discovery.js\";\n\nconst CANONICAL_DIR = join(homedir(), \".agents\", \"skills\");\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 */\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(CANONICAL_DIR, { recursive: true });\n}\n\n/** Copy skill files to the canonical location */\nexport async function installToCanonical(\n sourcePath: string,\n skillName: string,\n): Promise<string> {\n await ensureCanonicalDir();\n\n const targetDir = join(CANONICAL_DIR, skillName);\n\n // Remove existing if it exists\n if (existsSync(targetDir)) {\n await rm(targetDir, { recursive: true });\n }\n\n await cp(sourcePath, targetDir, { recursive: true });\n\n return targetDir;\n}\n\n/** Create a symlink from an agent's skills directory 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 targetSkillsDir = isGlobal\n ? provider.pathSkills\n : join(projectDir ?? process.cwd(), provider.pathProjectSkills);\n\n if (!targetSkillsDir) {\n return { success: false, error: `Provider ${provider.id} has no skills directory` };\n }\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 return { success: true };\n } catch (err) {\n return {\n success: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n}\n\n/**\n * Install a skill from a local path to the canonical location and link to agents.\n *\n * Copies the skill directory to `~/.agents/skills/<name>/` 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);\n * ```\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 * Removes symlinks from each provider's skills directory and then removes the\n * canonical copy from `~/.agents/skills/<name>/`.\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);\n * ```\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\n for (const provider of providers) {\n const skillsDir = isGlobal\n ? provider.pathSkills\n : join(projectDir ?? process.cwd(), provider.pathProjectSkills);\n\n if (!skillsDir) continue;\n\n const linkPath = join(skillsDir, skillName);\n if (existsSync(linkPath)) {\n try {\n await rm(linkPath, { recursive: true });\n removed.push(provider.id);\n } catch (err) {\n errors.push(`${provider.id}: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n }\n\n // Remove canonical copy\n const canonicalPath = join(CANONICAL_DIR, 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 directory (`~/.agents/skills/`).\n *\n * Returns the directory names of all skills, which correspond to skill names.\n *\n * @returns Array of skill names\n *\n * @example\n * ```typescript\n * const skills = await listCanonicalSkills();\n * // [\"my-skill\", \"another-skill\"]\n * ```\n */\nexport async function listCanonicalSkills(): Promise<string[]> {\n if (!existsSync(CANONICAL_DIR)) return [];\n\n const { readdir } = await import(\"node:fs/promises\");\n const entries = await readdir(CANONICAL_DIR, { withFileTypes: true });\n return entries\n .filter((e) => e.isDirectory() || e.isSymbolicLink())\n .map((e) => e.name);\n}\n","/**\n * Shared lock file utilities\n *\n * Single source of truth for reading/writing ~/.agents/.caamp-lock.json.\n * Both MCP and skills lock modules import from here.\n */\n\nimport { readFile, writeFile, mkdir } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type { CaampLockFile } from \"../types.js\";\n\nconst LOCK_DIR = join(homedir(), \".agents\");\nconst LOCK_FILE = join(LOCK_DIR, \".caamp-lock.json\");\n\n/** Read the lock file */\nexport async function readLockFile(): Promise<CaampLockFile> {\n try {\n if (!existsSync(LOCK_FILE)) {\n return { version: 1, skills: {}, mcpServers: {} };\n }\n const content = await readFile(LOCK_FILE, \"utf-8\");\n return JSON.parse(content) as CaampLockFile;\n } catch {\n return { version: 1, skills: {}, mcpServers: {} };\n }\n}\n\n/** Write the lock file */\nexport async function writeLockFile(lock: CaampLockFile): Promise<void> {\n await mkdir(LOCK_DIR, { recursive: true });\n await writeFile(LOCK_FILE, JSON.stringify(lock, null, 2) + \"\\n\", \"utf-8\");\n}\n","/**\n * Skills lock file management\n *\n * Shares the same lock file as MCP (~/.agents/.caamp-lock.json).\n */\n\nimport type { LockEntry, SourceType } from \"../../types.js\";\nimport { readLockFile, writeLockFile } from \"../lock-utils.js\";\nimport { parseSource } from \"../sources/parser.js\";\nimport { simpleGit } from \"simple-git\";\n\n/**\n * Record a skill installation in the lock file.\n *\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 * await recordSkillInstall(\n * \"my-skill\", \"my-skill\", \"owner/repo\", \"github\",\n * [\"claude-code\"], \"/home/user/.agents/skills/my-skill\", true,\n * );\n * ```\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 const lock = await readLockFile();\n const now = new Date().toISOString();\n\n const existing = lock.skills[skillName];\n\n lock.skills[skillName] = {\n name: skillName,\n scopedName,\n source,\n sourceType,\n version,\n installedAt: existing?.installedAt ?? now,\n updatedAt: now,\n agents: [...new Set([...(existing?.agents ?? []), ...agents])],\n canonicalPath,\n isGlobal,\n projectDir,\n };\n\n await writeLockFile(lock);\n}\n\n/**\n * Remove a skill entry from the lock file.\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 * ```\n */\nexport async function removeSkillFromLock(skillName: string): Promise<boolean> {\n const lock = await readLockFile();\n if (!(skillName in lock.skills)) return false;\n\n delete lock.skills[skillName];\n await writeLockFile(lock);\n return true;\n}\n\n/**\n * Get all skills tracked in the lock file.\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 */\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/**\n * Check if a skill has updates available by comparing the installed version\n * against the latest remote commit SHA.\n *\n * Only supports GitHub and GitLab 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 */\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 and GitLab sources support remote checking\n if (entry.sourceType !== \"github\" && entry.sourceType !== \"gitlab\") {\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 || !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 * 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\";\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\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\nexport class SkillsMPAdapter implements MarketplaceAdapter {\n name = \"agentskills.in\";\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 try {\n const response = await fetch(`${API_BASE}?${params}`);\n if (!response.ok) return [];\n\n const data = (await response.json()) as ApiResponse;\n return data.skills.map(toResult);\n } catch {\n return [];\n }\n }\n\n async getSkill(scopedName: string): Promise<MarketplaceResult | null> {\n const params = new URLSearchParams({\n search: scopedName,\n limit: \"1\",\n });\n\n try {\n const response = await fetch(`${API_BASE}?${params}`);\n if (!response.ok) return null;\n\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 return match ? toResult(match) : null;\n } catch {\n return null;\n }\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\";\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\nexport class SkillsShAdapter implements MarketplaceAdapter {\n name = \"skills.sh\";\n\n async search(query: string, limit = 20): Promise<MarketplaceResult[]> {\n try {\n const params = new URLSearchParams({\n q: query,\n limit: String(limit),\n });\n\n const response = await fetch(`${API_BASE}/search?${params}`);\n if (!response.ok) return [];\n\n const data = (await response.json()) as SkillsShResponse;\n return data.results.map(toResult);\n } catch {\n return [];\n }\n }\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 * 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 * @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 */\nexport class MarketplaceClient {\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 // Query all adapters in parallel\n const promises = this.adapters.map((adapter) =>\n adapter.search(query, limit).catch(() => [] as MarketplaceResult[]),\n );\n\n const allResults = await Promise.all(promises);\n const flat = allResults.flat();\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 for (const adapter of this.adapters) {\n const result = await adapter.getSkill(scopedName).catch(() => null);\n if (result) return result;\n }\n return null;\n }\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, dirname, basename } 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 * 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 */\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 * 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 * const skill = await discoverSkill(\"/home/user/.agents/skills/my-skill\");\n * if (skill) {\n * console.log(`Found: ${skill.name}`);\n * }\n * ```\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 * 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 * const skills = await discoverSkills(\"/home/user/.agents/skills\");\n * console.log(`Found ${skills.length} skills`);\n * ```\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/** Discover skills across multiple directories */\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 * 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 { readFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport type { AuditResult, AuditFinding, 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 * 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 */\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 * 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 * const results = await scanDirectory(\"/home/user/.agents/skills\");\n * const failing = results.filter(r => !r.passed);\n * ```\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 * 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 */\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\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/** Get rules by category */\nexport function getRulesByCategory(category: string): AuditRule[] {\n return AUDIT_RULES.filter((r) => r.category === category);\n}\n\n/** Get rules by severity */\nexport function getRulesBySeverity(severity: AuditSeverity): AuditRule[] {\n return AUDIT_RULES.filter((r) => r.severity === severity);\n}\n\n/** Get all unique categories */\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 */\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 */\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 * 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 */\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","/**\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 * @example\n * ```typescript\n * deepMerge({ a: 1, b: { c: 2 } }, { b: { d: 3 } });\n * // { a: 1, b: { c: 2, d: 3 } }\n * ```\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/** Set a nested value using dot-notation key path */\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 (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 * @example\n * ```typescript\n * getNestedValue({ a: { b: { c: 42 } } }, \"a.b.c\"); // 42\n * getNestedValue({ a: 1 }, \"a.b\"); // undefined\n * ```\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 * @example\n * ```typescript\n * await ensureDir(\"/path/to/new/dir/file.json\");\n * // /path/to/new/dir/ now exists\n * ```\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 * 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 { deepMerge, setNestedValue, ensureDir } from \"./utils.js\";\n\n/** Read a JSON/JSONC config file */\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/** Write a server config to a JSON/JSONC file, preserving comments */\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/** Remove a server entry from a JSON/JSONC config */\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 { readFile, writeFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport yaml from \"js-yaml\";\nimport { deepMerge, ensureDir } from \"./utils.js\";\n\n/** Read a YAML config file */\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/** Write a server config to a YAML file */\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 (let i = keyParts.length - 1; i >= 0; i--) {\n newEntry = { [keyParts[i]!]: 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/** Remove a server entry from a YAML config */\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 { readFile, writeFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport TOML from \"@iarna/toml\";\nimport { deepMerge, ensureDir } from \"./utils.js\";\n\n/** Read a TOML config file */\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/** Write a server config to a TOML file */\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 (let i = keyParts.length - 1; i >= 0; i--) {\n newEntry = { [keyParts[i]!]: 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/** Remove a server entry from a TOML config */\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 * Format router - dispatches config reads/writes to format-specific handlers\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 * @example\n * ```typescript\n * const config = await readConfig(\"/path/to/config.json\", \"jsonc\");\n * ```\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 * @example\n * ```typescript\n * await writeConfig(\"/path/to/config.json\", \"jsonc\", \"mcpServers\", \"my-server\", config);\n * ```\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 * @example\n * ```typescript\n * const removed = await removeConfig(\"/path/to/config.json\", \"jsonc\", \"mcpServers\", \"my-server\");\n * ```\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 * 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/** Transform config for Goose (YAML extensions format) */\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/** Transform config for Zed (context_servers format) */\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/** Transform config for OpenCode (mcp format) */\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,\n args: config.args ?? [],\n enabled: true,\n ...(config.env ? { environment: config.env } : {}),\n };\n}\n\n/** Transform config for Codex (TOML mcp_servers format) */\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/** Transform config for Cursor (mcpServers format - strips type field for remote) */\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 * @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\", canonicalConfig);\n * }\n * ```\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 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 { join } from \"node:path\";\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\";\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 * @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 path = resolveConfigPath(provider, \"project\", \"/home/user/my-project\");\n * // \"/home/user/my-project/.claude/settings.json\"\n * ```\n */\nexport function resolveConfigPath(\n provider: Provider,\n scope: \"project\" | \"global\",\n projectDir?: string,\n): string | null {\n if (scope === \"project\") {\n if (!provider.configPathProject) return null;\n return join(projectDir ?? process.cwd(), provider.configPathProject);\n }\n return provider.configPathGlobal;\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 * @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 servers = await listMcpServers(provider, \"project\");\n * for (const s of servers) {\n * console.log(`${s.name} (${s.scope})`);\n * }\n * ```\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 across all given providers, deduplicating by config path.\n *\n * Multiple providers may share the same config file. This function ensures each\n * config file is read only once to avoid duplicate entries.\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 allServers = await listAllMcpServers(getInstalledProviders(), \"global\");\n * ```\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 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 * @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 removed = await removeMcpServer(provider, \"my-server\", \"project\");\n * ```\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 * 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 { Provider, McpServerConfig, GlobalOptions } from \"../../types.js\";\nimport { writeConfig } from \"../formats/index.js\";\nimport { getTransform } from \"./transforms.js\";\nimport { resolveConfigPath } from \"./reader.js\";\nimport { debug } from \"../logger.js\";\n\n/**\n * Result of installing an MCP server configuration to a single provider.\n *\n * @example\n * ```typescript\n * const result = await installMcpServer(provider, \"my-server\", config);\n * if (result.success) {\n * console.log(`Written to ${result.configPath}`);\n * }\n * ```\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. */\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 * @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 * });\n * ```\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 * @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 results = await installMcpServerToAll(providers, \"my-server\", config);\n * const successes = results.filter(r => r.success);\n * ```\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 * @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\" });\n * // { command: \"npx\", args: [\"-y\", \"@mcp/server-fs\"] }\n *\n * buildServerConfig({ type: \"remote\", value: \"https://mcp.example.com\" });\n * // { type: \"http\", url: \"https://mcp.example.com\" }\n * ```\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.split(/\\s+/);\n return {\n command: parts[0]!,\n args: parts.slice(1),\n };\n}\n","/**\n * MCP lock file management\n *\n * Tracks installed MCP servers with source and agent metadata.\n * Stored at ~/.agents/.caamp-lock.json (shared with skills lock).\n */\n\nimport type { LockEntry, SourceType } from \"../../types.js\";\nimport { readLockFile, writeLockFile } from \"../lock-utils.js\";\n\n/**\n * Read and parse the CAAMP lock file from `~/.agents/.caamp-lock.json`.\n *\n * Returns the full {@link CaampLockFile} structure. Creates a default lock file\n * if one does not exist.\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 */\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 * @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 *\n * @example\n * ```typescript\n * await recordMcpInstall(\"filesystem\", \"@mcp/server-fs\", \"package\", [\"claude-code\"], true);\n * ```\n */\nexport async function recordMcpInstall(\n serverName: string,\n source: string,\n sourceType: SourceType,\n agents: string[],\n isGlobal: boolean,\n): Promise<void> {\n const lock = await readLockFile();\n const now = new Date().toISOString();\n\n const existing = lock.mcpServers[serverName];\n\n lock.mcpServers[serverName] = {\n name: serverName,\n scopedName: serverName,\n source,\n sourceType,\n installedAt: existing?.installedAt ?? now,\n updatedAt: now,\n agents: [...new Set([...(existing?.agents ?? []), ...agents])],\n canonicalPath: \"\",\n isGlobal,\n };\n\n await writeLockFile(lock);\n}\n\n/**\n * Remove an MCP server entry from the lock file.\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 * ```\n */\nexport async function removeMcpFromLock(serverName: string): Promise<boolean> {\n const lock = await readLockFile();\n if (!(serverName in lock.mcpServers)) return false;\n\n delete lock.mcpServers[serverName];\n await writeLockFile(lock);\n return true;\n}\n\n/**\n * Get all MCP servers tracked in the lock file.\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 */\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 * @param agents - Array of provider IDs to remember\n *\n * @example\n * ```typescript\n * await saveLastSelectedAgents([\"claude-code\", \"cursor\"]);\n * ```\n */\nexport async function saveLastSelectedAgents(agents: string[]): Promise<void> {\n const lock = await readLockFile();\n lock.lastSelectedAgents = agents;\n await writeLockFile(lock);\n}\n\n/**\n * Retrieve the last selected agent IDs from the lock file.\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 */\nexport async function getLastSelectedAgents(): Promise<string[] | undefined> {\n const lock = await readLockFile();\n return lock.lastSelectedAgents;\n}\n","/**\n * Marker-based instruction file injection\n *\n * Injects content blocks between CAAMP markers in instruction files\n * (CLAUDE.md, AGENTS.md, GEMINI.md).\n */\n\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport { join, dirname } from \"node:path\";\nimport { mkdir } from \"node:fs/promises\";\nimport type { InjectionStatus, InjectionCheckResult, Provider } from \"../../types.js\";\n\nconst MARKER_START = \"<!-- CAAMP:START -->\";\nconst MARKER_END = \"<!-- CAAMP:END -->\";\nconst MARKER_PATTERN = /<!-- CAAMP:START -->[\\s\\S]*?<!-- CAAMP:END -->/;\n\n/**\n * Check the status of a CAAMP injection block in an instruction file.\n *\n * Returns the injection status:\n * - `\"missing\"` - File does not exist\n * - `\"none\"` - File exists but has no CAAMP markers\n * - `\"current\"` - CAAMP block exists and matches expected content (or no expected content given)\n * - `\"outdated\"` - CAAMP block exists but differs from expected content\n *\n * @param filePath - Absolute path to the instruction file\n * @param expectedContent - Optional expected content to compare against\n * @returns The injection status\n *\n * @example\n * ```typescript\n * const status = await checkInjection(\"/project/CLAUDE.md\", expectedContent);\n * if (status === \"outdated\") {\n * console.log(\"CAAMP injection needs updating\");\n * }\n * ```\n */\nexport async function checkInjection(\n filePath: string,\n expectedContent?: string,\n): Promise<InjectionStatus> {\n if (!existsSync(filePath)) return \"missing\";\n\n const content = await readFile(filePath, \"utf-8\");\n\n if (!MARKER_PATTERN.test(content)) return \"none\";\n\n if (expectedContent) {\n const blockContent = extractBlock(content);\n if (blockContent && blockContent.trim() === expectedContent.trim()) {\n return \"current\";\n }\n return \"outdated\";\n }\n\n return \"current\";\n}\n\n/** Extract the content between CAAMP markers */\nfunction extractBlock(content: string): string | null {\n const match = content.match(MARKER_PATTERN);\n if (!match) return null;\n\n return match[0]\n .replace(MARKER_START, \"\")\n .replace(MARKER_END, \"\")\n .trim();\n}\n\n/** Build the injection block */\nfunction buildBlock(content: string): string {\n return `${MARKER_START}\\n${content}\\n${MARKER_END}`;\n}\n\n/**\n * Inject content into an instruction file between CAAMP markers.\n *\n * Behavior depends on the file state:\n * - File does not exist: creates the file with the injection block\n * - File exists without markers: prepends the injection block\n * - File exists with markers: replaces the existing injection block\n *\n * @param filePath - Absolute path to the instruction file\n * @param content - Content to inject between CAAMP markers\n * @returns Action taken: `\"created\"`, `\"added\"`, or `\"updated\"`\n *\n * @example\n * ```typescript\n * const action = await inject(\"/project/CLAUDE.md\", \"## My Config\\nSome content\");\n * console.log(`File ${action}`);\n * ```\n */\nexport async function inject(\n filePath: string,\n content: string,\n): Promise<\"created\" | \"added\" | \"updated\"> {\n const block = buildBlock(content);\n\n // Ensure parent directory exists\n await mkdir(dirname(filePath), { recursive: true });\n\n if (!existsSync(filePath)) {\n // Create new file with injection block\n await writeFile(filePath, block + \"\\n\", \"utf-8\");\n return \"created\";\n }\n\n const existing = await readFile(filePath, \"utf-8\");\n\n if (MARKER_PATTERN.test(existing)) {\n // Replace existing block\n const updated = existing.replace(MARKER_PATTERN, block);\n await writeFile(filePath, updated, \"utf-8\");\n return \"updated\";\n }\n\n // Prepend block to existing content\n const updated = block + \"\\n\\n\" + existing;\n await writeFile(filePath, updated, \"utf-8\");\n return \"added\";\n}\n\n/**\n * Remove the CAAMP injection block from an instruction file.\n *\n * If removing the block would leave the file empty, the file is deleted entirely.\n *\n * @param filePath - Absolute path to the instruction file\n * @returns `true` if a CAAMP block was found and removed, `false` otherwise\n *\n * @example\n * ```typescript\n * const removed = await removeInjection(\"/project/CLAUDE.md\");\n * ```\n */\nexport async function removeInjection(filePath: string): Promise<boolean> {\n if (!existsSync(filePath)) return false;\n\n const content = await readFile(filePath, \"utf-8\");\n if (!MARKER_PATTERN.test(content)) return false;\n\n const cleaned = content\n .replace(MARKER_PATTERN, \"\")\n .replace(/^\\n{2,}/, \"\\n\")\n .trim();\n\n if (!cleaned) {\n // File would be empty - remove it entirely\n const { rm } = await import(\"node:fs/promises\");\n await rm(filePath);\n } else {\n await writeFile(filePath, cleaned + \"\\n\", \"utf-8\");\n }\n\n return true;\n}\n\n/**\n * Check injection status across all providers' instruction files.\n *\n * Deduplicates by file path since multiple providers may share the same\n * instruction file (e.g. many providers use `AGENTS.md`).\n *\n * @param providers - Array of providers to check\n * @param projectDir - Absolute path to the project directory\n * @param scope - Whether to check project or global instruction files\n * @param expectedContent - Optional expected content to compare against\n * @returns Array of injection check results, one per unique instruction file\n *\n * @example\n * ```typescript\n * const results = await checkAllInjections(providers, \"/project\", \"project\");\n * const outdated = results.filter(r => r.status === \"outdated\");\n * ```\n */\nexport async function checkAllInjections(\n providers: Provider[],\n projectDir: string,\n scope: \"project\" | \"global\",\n expectedContent?: string,\n): Promise<InjectionCheckResult[]> {\n const results: InjectionCheckResult[] = [];\n const checked = new Set<string>();\n\n for (const provider of providers) {\n const filePath = scope === \"global\"\n ? join(provider.pathGlobal, provider.instructFile)\n : join(projectDir, provider.instructFile);\n\n // Skip duplicates (multiple providers share same instruction file)\n if (checked.has(filePath)) continue;\n checked.add(filePath);\n\n const status = await checkInjection(filePath, expectedContent);\n\n results.push({\n file: filePath,\n provider: provider.id,\n status,\n fileExists: existsSync(filePath),\n });\n }\n\n return results;\n}\n\n/**\n * Inject content into all providers' instruction files.\n *\n * Deduplicates by file path to avoid injecting the same file multiple times.\n *\n * @param providers - Array of providers to inject into\n * @param projectDir - Absolute path to the project directory\n * @param scope - Whether to target project or global instruction files\n * @param content - Content to inject between CAAMP markers\n * @returns Map of file path to action taken (`\"created\"`, `\"added\"`, or `\"updated\"`)\n *\n * @example\n * ```typescript\n * const results = await injectAll(providers, \"/project\", \"project\", content);\n * for (const [file, action] of results) {\n * console.log(`${file}: ${action}`);\n * }\n * ```\n */\nexport async function injectAll(\n providers: Provider[],\n projectDir: string,\n scope: \"project\" | \"global\",\n content: string,\n): Promise<Map<string, \"created\" | \"added\" | \"updated\">> {\n const results = new Map<string, \"created\" | \"added\" | \"updated\">();\n const injected = new Set<string>();\n\n for (const provider of providers) {\n const filePath = scope === \"global\"\n ? join(provider.pathGlobal, provider.instructFile)\n : join(projectDir, provider.instructFile);\n\n // Skip duplicates\n if (injected.has(filePath)) continue;\n injected.add(filePath);\n\n const action = await inject(filePath, content);\n results.set(filePath, action);\n }\n\n return results;\n}\n","/**\n * Instruction template management\n *\n * Generates injection content based on provider capabilities.\n */\n\nimport type { Provider } from \"../../types.js\";\n\n/**\n * Generate a standard CAAMP injection block for instruction files.\n *\n * Produces markdown content suitable for injection between CAAMP markers.\n * Optionally includes MCP server and custom content sections.\n *\n * @param options - Optional configuration for the generated content\n * @param options.mcpServerName - MCP server name to include a server section\n * @param options.customContent - Additional custom markdown content to append\n * @returns Generated markdown string\n *\n * @example\n * ```typescript\n * const content = generateInjectionContent({ mcpServerName: \"filesystem\" });\n * ```\n */\nexport function generateInjectionContent(options?: {\n mcpServerName?: string;\n customContent?: string;\n}): string {\n const lines: string[] = [];\n\n lines.push(\"## CAAMP Managed Configuration\");\n lines.push(\"\");\n lines.push(\"This section is managed by [CAAMP](https://github.com/caamp/caamp).\");\n lines.push(\"Do not edit between the CAAMP markers manually.\");\n\n if (options?.mcpServerName) {\n lines.push(\"\");\n lines.push(`### MCP Server: ${options.mcpServerName}`);\n lines.push(`Configured via \\`caamp mcp install\\`.`);\n }\n\n if (options?.customContent) {\n lines.push(\"\");\n lines.push(options.customContent);\n }\n\n return lines.join(\"\\n\");\n}\n\n/** Generate a skills discovery section for instruction files */\nexport function generateSkillsSection(skillNames: string[]): string {\n if (skillNames.length === 0) return \"\";\n\n const lines: string[] = [];\n lines.push(\"### Installed Skills\");\n lines.push(\"\");\n\n for (const name of skillNames) {\n lines.push(`- \\`${name}\\` - Available via SKILL.md`);\n }\n\n return lines.join(\"\\n\");\n}\n\n/** Get the correct instruction file name for a provider */\nexport function getInstructFile(provider: Provider): string {\n return provider.instructFile;\n}\n\n/**\n * Group providers by their instruction file name.\n *\n * Useful for determining which providers share the same instruction file\n * (e.g. multiple providers using `AGENTS.md`).\n *\n * @param providers - Array of providers to group\n * @returns Map from instruction file name to array of providers using that file\n *\n * @example\n * ```typescript\n * const groups = groupByInstructFile(getAllProviders());\n * for (const [file, providers] of groups) {\n * console.log(`${file}: ${providers.map(p => p.id).join(\", \")}`);\n * }\n * ```\n */\nexport function groupByInstructFile(providers: Provider[]): Map<string, Provider[]> {\n const groups = new Map<string, Provider[]>();\n\n for (const provider of providers) {\n const existing = groups.get(provider.instructFile) ?? [];\n existing.push(provider);\n groups.set(provider.instructFile, existing);\n }\n\n return groups;\n}\n"],"mappings":"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","names":["existsSync","join","existsSync","join","existsSync","homedir","join","readdir","readFile","writeFile","mkdir","existsSync","homedir","join","API_BASE","toResult","readFile","existsSync","join","readFile","existsSync","existsSync","readFile","rule","readdir","join","readFile","existsSync","matter","mkdir","dirname","readFile","writeFile","existsSync","existsSync","readFile","writeFile","readFile","writeFile","existsSync","existsSync","readFile","writeFile","readFile","writeFile","existsSync","existsSync","readFile","writeFile","join","existsSync","join","existsSync","readFile","writeFile","existsSync","join","dirname","mkdir","updated","rm"]}