@codemcp/skills 1.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.mjs","names":["pc","simpleGit","AGENTS_DIR","AGENTS_DIR","AGENTS_DIR","LOCK_FILE","CURRENT_VERSION","getSkillLockPath","readSkillLock","isCancelled","pc","shortenPath","formatList","p.multiselect","packageJson.version","p.select","p.isCancel","p.confirm","p.spinner","p.groupMultiselect","RESET","BOLD","DIM","TEXT","CYAN","shortenPath","pc","p.spinner","p.confirm","p.isCancel","pc","RESET","BOLD","DIM","p.spinner","pc","p.multiselect","p.isCancel","p.confirm","fs","p.text","pc","p.isCancel","fs","select","multiselect"],"sources":["../src/source-parser.ts","../src/prompts/search-multiselect.ts","../src/git.ts","../src/plugin-manifest.ts","../src/skills.ts","../src/agents.ts","../src/constants.ts","../src/installer.ts","../src/telemetry.ts","../src/providers/registry.ts","../src/providers/mintlify.ts","../src/providers/huggingface.ts","../src/providers/wellknown.ts","../src/providers/index.ts","../src/mintlify.ts","../src/skill-lock.ts","../src/local-lock.ts","../package.json","../src/add.ts","../src/find.ts","../src/sync.ts","../src/install.ts","../src/list.ts","../src/remove.ts","../src/mcp-configurator.ts","../src/mcp-skill-deps.ts","../src/mcp.ts","../src/cli.ts"],"sourcesContent":["import { isAbsolute, resolve } from 'path';\nimport type { ParsedSource } from './types.ts';\n\n/**\n * Extract owner/repo (or group/subgroup/repo for GitLab) from a parsed source\n * for lockfile tracking and telemetry.\n * Returns null for local paths or unparseable sources.\n * Supports any Git host with an owner/repo URL structure, including GitLab subgroups.\n */\nexport function getOwnerRepo(parsed: ParsedSource): string | null {\n if (parsed.type === 'local') {\n return null;\n }\n\n // Only handle HTTP(S) URLs\n if (!parsed.url.startsWith('http://') && !parsed.url.startsWith('https://')) {\n return null;\n }\n\n try {\n const url = new URL(parsed.url);\n // Get pathname, remove leading slash and trailing .git\n let path = url.pathname.slice(1);\n path = path.replace(/\\.git$/, '');\n\n // Must have at least owner/repo (one slash)\n if (path.includes('/')) {\n return path;\n }\n } catch {\n // Invalid URL\n }\n\n return null;\n}\n\n/**\n * Extract owner and repo from an owner/repo string.\n * Returns null if the format is invalid.\n */\nexport function parseOwnerRepo(ownerRepo: string): { owner: string; repo: string } | null {\n const match = ownerRepo.match(/^([^/]+)\\/([^/]+)$/);\n if (match) {\n return { owner: match[1]!, repo: match[2]! };\n }\n return null;\n}\n\n/**\n * Check if a GitHub repository is private.\n * Returns true if private, false if public, null if unable to determine.\n * Only works for GitHub repositories (GitLab not supported).\n */\nexport async function isRepoPrivate(owner: string, repo: string): Promise<boolean | null> {\n try {\n const res = await fetch(`https://api.github.com/repos/${owner}/${repo}`);\n\n // If repo doesn't exist or we don't have access, assume private to be safe\n if (!res.ok) {\n return null; // Unable to determine\n }\n\n const data = (await res.json()) as { private?: boolean };\n return data.private === true;\n } catch {\n // On error, return null to indicate we couldn't determine\n return null;\n }\n}\n\n/**\n * Check if a string represents a local file system path\n */\nfunction isLocalPath(input: string): boolean {\n return (\n isAbsolute(input) ||\n input.startsWith('./') ||\n input.startsWith('../') ||\n input === '.' ||\n input === '..' ||\n // Windows absolute paths like C:\\ or D:\\\n /^[a-zA-Z]:[/\\\\]/.test(input)\n );\n}\n\n/**\n * Check if a URL is a direct link to a skill.md file.\n * Supports various hosts: Mintlify docs, HuggingFace Spaces, etc.\n * e.g., https://docs.bun.com/docs/skill.md\n * e.g., https://huggingface.co/spaces/owner/repo/blob/main/SKILL.md\n *\n * Note: GitHub and GitLab URLs are excluded as they have their own handling\n * for cloning repositories.\n */\nfunction isDirectSkillUrl(input: string): boolean {\n if (!input.startsWith('http://') && !input.startsWith('https://')) {\n return false;\n }\n\n // Must end with skill.md (case insensitive)\n if (!input.toLowerCase().endsWith('/skill.md')) {\n return false;\n }\n\n // Exclude GitHub and GitLab repository URLs - they have their own handling\n // (but allow raw.githubusercontent.com if someone wants to use it directly)\n if (input.includes('github.com/') && !input.includes('raw.githubusercontent.com')) {\n // Check if it's a blob/raw URL to SKILL.md (these should be handled by providers)\n // vs a tree/repo URL (these should be cloned)\n if (!input.includes('/blob/') && !input.includes('/raw/')) {\n return false;\n }\n }\n if (input.includes('gitlab.com/') && !input.includes('/-/raw/')) {\n return false;\n }\n\n return true;\n}\n\n/**\n * Parse a source string into a structured format\n * Supports: local paths, GitHub URLs, GitLab URLs, GitHub shorthand, direct skill.md URLs, and direct git URLs\n */\n// Source aliases: map common shorthand to canonical source\nconst SOURCE_ALIASES: Record<string, string> = {\n 'coinbase/agentWallet': 'coinbase/agentic-wallet-skills',\n};\n\nexport function parseSource(input: string): ParsedSource {\n // Resolve source aliases before parsing\n const alias = SOURCE_ALIASES[input];\n if (alias) {\n input = alias;\n }\n\n // Local path: absolute, relative, or current directory\n if (isLocalPath(input)) {\n const resolvedPath = resolve(input);\n // Return local type even if path doesn't exist - we'll handle validation in main flow\n return {\n type: 'local',\n url: resolvedPath, // Store resolved path in url for consistency\n localPath: resolvedPath,\n };\n }\n\n // Direct skill.md URL (non-GitHub/GitLab): https://docs.bun.com/docs/skill.md\n if (isDirectSkillUrl(input)) {\n return {\n type: 'direct-url',\n url: input,\n };\n }\n\n // GitHub URL with path: https://github.com/owner/repo/tree/branch/path/to/skill\n const githubTreeWithPathMatch = input.match(/github\\.com\\/([^/]+)\\/([^/]+)\\/tree\\/([^/]+)\\/(.+)/);\n if (githubTreeWithPathMatch) {\n const [, owner, repo, ref, subpath] = githubTreeWithPathMatch;\n return {\n type: 'github',\n url: `https://github.com/${owner}/${repo}.git`,\n ref,\n subpath,\n };\n }\n\n // GitHub URL with branch only: https://github.com/owner/repo/tree/branch\n const githubTreeMatch = input.match(/github\\.com\\/([^/]+)\\/([^/]+)\\/tree\\/([^/]+)$/);\n if (githubTreeMatch) {\n const [, owner, repo, ref] = githubTreeMatch;\n return {\n type: 'github',\n url: `https://github.com/${owner}/${repo}.git`,\n ref,\n };\n }\n\n // GitHub URL: https://github.com/owner/repo\n const githubRepoMatch = input.match(/github\\.com\\/([^/]+)\\/([^/]+)/);\n if (githubRepoMatch) {\n const [, owner, repo] = githubRepoMatch;\n const cleanRepo = repo!.replace(/\\.git$/, '');\n return {\n type: 'github',\n url: `https://github.com/${owner}/${cleanRepo}.git`,\n };\n }\n\n // GitLab URL with path (any GitLab instance): https://gitlab.com/owner/repo/-/tree/branch/path\n // Key identifier is the \"/-/tree/\" path pattern unique to GitLab.\n // Supports subgroups by using a non-greedy match for the repository path.\n const gitlabTreeWithPathMatch = input.match(\n /^(https?):\\/\\/([^/]+)\\/(.+?)\\/-\\/tree\\/([^/]+)\\/(.+)/\n );\n if (gitlabTreeWithPathMatch) {\n const [, protocol, hostname, repoPath, ref, subpath] = gitlabTreeWithPathMatch;\n if (hostname !== 'github.com' && repoPath) {\n return {\n type: 'gitlab',\n url: `${protocol}://${hostname}/${repoPath.replace(/\\.git$/, '')}.git`,\n ref,\n subpath,\n };\n }\n }\n\n // GitLab URL with branch only (any GitLab instance): https://gitlab.com/owner/repo/-/tree/branch\n const gitlabTreeMatch = input.match(/^(https?):\\/\\/([^/]+)\\/(.+?)\\/-\\/tree\\/([^/]+)$/);\n if (gitlabTreeMatch) {\n const [, protocol, hostname, repoPath, ref] = gitlabTreeMatch;\n if (hostname !== 'github.com' && repoPath) {\n return {\n type: 'gitlab',\n url: `${protocol}://${hostname}/${repoPath.replace(/\\.git$/, '')}.git`,\n ref,\n };\n }\n }\n\n // GitLab.com URL: https://gitlab.com/owner/repo or https://gitlab.com/group/subgroup/repo\n // Only for the official gitlab.com domain for user convenience.\n // Supports nested subgroups (e.g., gitlab.com/group/subgroup1/subgroup2/repo).\n const gitlabRepoMatch = input.match(/gitlab\\.com\\/(.+?)(?:\\.git)?\\/?$/);\n if (gitlabRepoMatch) {\n const repoPath = gitlabRepoMatch[1]!;\n // Must have at least owner/repo (one slash)\n if (repoPath.includes('/')) {\n return {\n type: 'gitlab',\n url: `https://gitlab.com/${repoPath}.git`,\n };\n }\n }\n\n // GitHub shorthand: owner/repo, owner/repo/path/to/skill, or owner/repo@skill-name\n // Exclude paths that start with . or / to avoid matching local paths\n // First check for @skill syntax: owner/repo@skill-name\n const atSkillMatch = input.match(/^([^/]+)\\/([^/@]+)@(.+)$/);\n if (atSkillMatch && !input.includes(':') && !input.startsWith('.') && !input.startsWith('/')) {\n const [, owner, repo, skillFilter] = atSkillMatch;\n return {\n type: 'github',\n url: `https://github.com/${owner}/${repo}.git`,\n skillFilter,\n };\n }\n\n const shorthandMatch = input.match(/^([^/]+)\\/([^/]+)(?:\\/(.+))?$/);\n if (shorthandMatch && !input.includes(':') && !input.startsWith('.') && !input.startsWith('/')) {\n const [, owner, repo, subpath] = shorthandMatch;\n return {\n type: 'github',\n url: `https://github.com/${owner}/${repo}.git`,\n subpath,\n };\n }\n\n // Well-known skills: arbitrary HTTP(S) URLs that aren't GitHub/GitLab\n // This is the final fallback for URLs - we'll check for /.well-known/skills/index.json\n if (isWellKnownUrl(input)) {\n return {\n type: 'well-known',\n url: input,\n };\n }\n\n // Fallback: treat as direct git URL\n return {\n type: 'git',\n url: input,\n };\n}\n\n/**\n * Check if a URL could be a well-known skills endpoint.\n * Must be HTTP(S) and not a known git host (GitHub, GitLab).\n * Also excludes URLs that look like git repos (.git suffix).\n */\nfunction isWellKnownUrl(input: string): boolean {\n if (!input.startsWith('http://') && !input.startsWith('https://')) {\n return false;\n }\n\n try {\n const parsed = new URL(input);\n\n // Exclude known git hosts that have their own handling\n const excludedHosts = [\n 'github.com',\n 'gitlab.com',\n 'huggingface.co',\n 'raw.githubusercontent.com',\n ];\n if (excludedHosts.includes(parsed.hostname)) {\n return false;\n }\n\n // Don't match URLs that look like direct skill.md links (handled by direct-url type)\n if (input.toLowerCase().endsWith('/skill.md')) {\n return false;\n }\n\n // Don't match URLs that look like git repos (should be handled by git type)\n if (input.endsWith('.git')) {\n return false;\n }\n\n return true;\n } catch {\n return false;\n }\n}\n","import * as readline from 'readline';\nimport { Writable } from 'stream';\nimport pc from 'picocolors';\n\n// Silent writable stream to prevent readline from echoing input\nconst silentOutput = new Writable({\n write(_chunk, _encoding, callback) {\n callback();\n },\n});\n\nexport interface SearchItem<T> {\n value: T;\n label: string;\n hint?: string;\n}\n\nexport interface LockedSection<T> {\n title: string;\n items: SearchItem<T>[];\n}\n\nexport interface SearchMultiselectOptions<T> {\n message: string;\n items: SearchItem<T>[];\n maxVisible?: number;\n initialSelected?: T[];\n /** If true, require at least one item to be selected before submitting */\n required?: boolean;\n /** Locked section shown above the searchable list - items are always selected and can't be toggled */\n lockedSection?: LockedSection<T>;\n}\n\nconst S_STEP_ACTIVE = pc.green('◆');\nconst S_STEP_CANCEL = pc.red('■');\nconst S_STEP_SUBMIT = pc.green('◇');\nconst S_RADIO_ACTIVE = pc.green('●');\nconst S_RADIO_INACTIVE = pc.dim('○');\nconst S_CHECKBOX_LOCKED = pc.green('✓');\nconst S_BULLET = pc.green('•');\nconst S_BAR = pc.dim('│');\nconst S_BAR_H = pc.dim('─');\n\nexport const cancelSymbol = Symbol('cancel');\n\n/**\n * Interactive search multiselect prompt.\n * Allows users to filter a long list by typing and select multiple items.\n * Optionally supports a \"locked\" section that displays always-selected items.\n */\nexport async function searchMultiselect<T>(\n options: SearchMultiselectOptions<T>\n): Promise<T[] | symbol> {\n const {\n message,\n items,\n maxVisible = 8,\n initialSelected = [],\n required = false,\n lockedSection,\n } = options;\n\n return new Promise((resolve) => {\n const rl = readline.createInterface({\n input: process.stdin,\n output: silentOutput,\n terminal: false,\n });\n\n // Enable raw mode for keypress detection\n if (process.stdin.isTTY) {\n process.stdin.setRawMode(true);\n }\n readline.emitKeypressEvents(process.stdin, rl);\n\n let query = '';\n let cursor = 0;\n const selected = new Set<T>(initialSelected);\n let lastRenderHeight = 0;\n\n // Locked items are always included in the result\n const lockedValues = lockedSection ? lockedSection.items.map((i) => i.value) : [];\n\n const filter = (item: SearchItem<T>, q: string): boolean => {\n if (!q) return true;\n const lowerQ = q.toLowerCase();\n return (\n item.label.toLowerCase().includes(lowerQ) ||\n String(item.value).toLowerCase().includes(lowerQ)\n );\n };\n\n const getFiltered = (): SearchItem<T>[] => {\n return items.filter((item) => filter(item, query));\n };\n\n const clearRender = (): void => {\n if (lastRenderHeight > 0) {\n // Move up and clear each line\n process.stdout.write(`\\x1b[${lastRenderHeight}A`);\n for (let i = 0; i < lastRenderHeight; i++) {\n process.stdout.write('\\x1b[2K\\x1b[1B');\n }\n process.stdout.write(`\\x1b[${lastRenderHeight}A`);\n }\n };\n\n const render = (state: 'active' | 'submit' | 'cancel' = 'active'): void => {\n clearRender();\n\n const lines: string[] = [];\n const filtered = getFiltered();\n\n // Header\n const icon =\n state === 'active' ? S_STEP_ACTIVE : state === 'cancel' ? S_STEP_CANCEL : S_STEP_SUBMIT;\n lines.push(`${icon} ${pc.bold(message)}`);\n\n if (state === 'active') {\n // Locked section (universal agents)\n if (lockedSection && lockedSection.items.length > 0) {\n lines.push(`${S_BAR}`);\n const lockedTitle = `${pc.bold(lockedSection.title)} ${pc.dim('── always included')}`;\n lines.push(`${S_BAR} ${S_BAR_H}${S_BAR_H} ${lockedTitle} ${S_BAR_H.repeat(12)}`);\n for (const item of lockedSection.items) {\n lines.push(`${S_BAR} ${S_BULLET} ${pc.bold(item.label)}`);\n }\n lines.push(`${S_BAR}`);\n lines.push(\n `${S_BAR} ${S_BAR_H}${S_BAR_H} ${pc.bold('Additional agents')} ${S_BAR_H.repeat(29)}`\n );\n }\n\n // Search input\n const searchLine = `${S_BAR} ${pc.dim('Search:')} ${query}${pc.inverse(' ')}`;\n lines.push(searchLine);\n\n // Hint\n lines.push(`${S_BAR} ${pc.dim('↑↓ move, space select, enter confirm')}`);\n lines.push(`${S_BAR}`);\n\n // Items\n const visibleStart = Math.max(\n 0,\n Math.min(cursor - Math.floor(maxVisible / 2), filtered.length - maxVisible)\n );\n const visibleEnd = Math.min(filtered.length, visibleStart + maxVisible);\n const visibleItems = filtered.slice(visibleStart, visibleEnd);\n\n if (filtered.length === 0) {\n lines.push(`${S_BAR} ${pc.dim('No matches found')}`);\n } else {\n for (let i = 0; i < visibleItems.length; i++) {\n const item = visibleItems[i]!;\n const actualIndex = visibleStart + i;\n const isSelected = selected.has(item.value);\n const isCursor = actualIndex === cursor;\n\n const radio = isSelected ? S_RADIO_ACTIVE : S_RADIO_INACTIVE;\n const label = isCursor ? pc.underline(item.label) : item.label;\n const hint = item.hint ? pc.dim(` (${item.hint})`) : '';\n\n const prefix = isCursor ? pc.cyan('❯') : ' ';\n lines.push(`${S_BAR} ${prefix} ${radio} ${label}${hint}`);\n }\n\n // Show count if more items\n const hiddenBefore = visibleStart;\n const hiddenAfter = filtered.length - visibleEnd;\n if (hiddenBefore > 0 || hiddenAfter > 0) {\n const parts: string[] = [];\n if (hiddenBefore > 0) parts.push(`↑ ${hiddenBefore} more`);\n if (hiddenAfter > 0) parts.push(`↓ ${hiddenAfter} more`);\n lines.push(`${S_BAR} ${pc.dim(parts.join(' '))}`);\n }\n }\n\n // Selected summary (include locked items)\n lines.push(`${S_BAR}`);\n const allSelectedLabels = [\n ...(lockedSection ? lockedSection.items.map((i) => i.label) : []),\n ...items.filter((item) => selected.has(item.value)).map((item) => item.label),\n ];\n if (allSelectedLabels.length === 0) {\n lines.push(`${S_BAR} ${pc.dim('Selected: (none)')}`);\n } else {\n const summary =\n allSelectedLabels.length <= 3\n ? allSelectedLabels.join(', ')\n : `${allSelectedLabels.slice(0, 3).join(', ')} +${allSelectedLabels.length - 3} more`;\n lines.push(`${S_BAR} ${pc.green('Selected:')} ${summary}`);\n }\n\n lines.push(`${pc.dim('└')}`);\n } else if (state === 'submit') {\n // Final state - show what was selected (including locked)\n const allSelectedLabels = [\n ...(lockedSection ? lockedSection.items.map((i) => i.label) : []),\n ...items.filter((item) => selected.has(item.value)).map((item) => item.label),\n ];\n lines.push(`${S_BAR} ${pc.dim(allSelectedLabels.join(', '))}`);\n } else if (state === 'cancel') {\n lines.push(`${S_BAR} ${pc.strikethrough(pc.dim('Cancelled'))}`);\n }\n\n process.stdout.write(lines.join('\\n') + '\\n');\n lastRenderHeight = lines.length;\n };\n\n const cleanup = (): void => {\n process.stdin.removeListener('keypress', keypressHandler);\n if (process.stdin.isTTY) {\n process.stdin.setRawMode(false);\n }\n rl.close();\n };\n\n const submit = (): void => {\n // If required and no locked items, don't allow submitting with no selection\n if (required && selected.size === 0 && lockedValues.length === 0) {\n return;\n }\n render('submit');\n cleanup();\n // Include locked values in the result\n resolve([...lockedValues, ...Array.from(selected)]);\n };\n\n const cancel = (): void => {\n render('cancel');\n cleanup();\n resolve(cancelSymbol);\n };\n\n // Handle keypresses\n const keypressHandler = (_str: string, key: readline.Key): void => {\n if (!key) return;\n\n const filtered = getFiltered();\n\n if (key.name === 'return') {\n submit();\n return;\n }\n\n if (key.name === 'escape' || (key.ctrl && key.name === 'c')) {\n cancel();\n return;\n }\n\n if (key.name === 'up') {\n cursor = Math.max(0, cursor - 1);\n render();\n return;\n }\n\n if (key.name === 'down') {\n cursor = Math.min(filtered.length - 1, cursor + 1);\n render();\n return;\n }\n\n if (key.name === 'space') {\n const item = filtered[cursor];\n if (item) {\n if (selected.has(item.value)) {\n selected.delete(item.value);\n } else {\n selected.add(item.value);\n }\n }\n render();\n return;\n }\n\n if (key.name === 'backspace') {\n query = query.slice(0, -1);\n cursor = 0;\n render();\n return;\n }\n\n // Regular character input\n if (key.sequence && !key.ctrl && !key.meta && key.sequence.length === 1) {\n query += key.sequence;\n cursor = 0;\n render();\n return;\n }\n };\n\n process.stdin.on('keypress', keypressHandler);\n\n // Initial render\n render();\n });\n}\n","import simpleGit from 'simple-git';\nimport { join, normalize, resolve, sep } from 'path';\nimport { mkdtemp, rm } from 'fs/promises';\nimport { tmpdir } from 'os';\n\nconst CLONE_TIMEOUT_MS = 60000; // 60 seconds\n\nexport class GitCloneError extends Error {\n readonly url: string;\n readonly isTimeout: boolean;\n readonly isAuthError: boolean;\n\n constructor(message: string, url: string, isTimeout = false, isAuthError = false) {\n super(message);\n this.name = 'GitCloneError';\n this.url = url;\n this.isTimeout = isTimeout;\n this.isAuthError = isAuthError;\n }\n}\n\nexport async function cloneRepo(url: string, ref?: string): Promise<string> {\n const tempDir = await mkdtemp(join(tmpdir(), 'skills-'));\n const git = simpleGit({\n timeout: { block: CLONE_TIMEOUT_MS },\n env: { ...process.env, GIT_TERMINAL_PROMPT: '0' },\n });\n const cloneOptions = ref ? ['--depth', '1', '--branch', ref] : ['--depth', '1'];\n\n try {\n await git.clone(url, tempDir, cloneOptions);\n return tempDir;\n } catch (error) {\n // Clean up temp dir on failure\n await rm(tempDir, { recursive: true, force: true }).catch(() => {});\n\n const errorMessage = error instanceof Error ? error.message : String(error);\n const isTimeout = errorMessage.includes('block timeout') || errorMessage.includes('timed out');\n const isAuthError =\n errorMessage.includes('Authentication failed') ||\n errorMessage.includes('could not read Username') ||\n errorMessage.includes('Permission denied') ||\n errorMessage.includes('Repository not found');\n\n if (isTimeout) {\n throw new GitCloneError(\n `Clone timed out after 60s. This often happens with private repos that require authentication.\\n` +\n ` Ensure you have access and your SSH keys or credentials are configured:\\n` +\n ` - For SSH: ssh-add -l (to check loaded keys)\\n` +\n ` - For HTTPS: gh auth status (if using GitHub CLI)`,\n url,\n true,\n false\n );\n }\n\n if (isAuthError) {\n throw new GitCloneError(\n `Authentication failed for ${url}.\\n` +\n ` - For private repos, ensure you have access\\n` +\n ` - For SSH: Check your keys with 'ssh -T git@github.com'\\n` +\n ` - For HTTPS: Run 'gh auth login' or configure git credentials`,\n url,\n false,\n true\n );\n }\n\n throw new GitCloneError(`Failed to clone ${url}: ${errorMessage}`, url, false, false);\n }\n}\n\nexport async function cleanupTempDir(dir: string): Promise<void> {\n // Validate that the directory path is within tmpdir to prevent deletion of arbitrary paths\n const normalizedDir = normalize(resolve(dir));\n const normalizedTmpDir = normalize(resolve(tmpdir()));\n\n if (!normalizedDir.startsWith(normalizedTmpDir + sep) && normalizedDir !== normalizedTmpDir) {\n throw new Error('Attempted to clean up directory outside of temp directory');\n }\n\n await rm(dir, { recursive: true, force: true });\n}\n","import { readFile } from 'fs/promises';\nimport { join, dirname, resolve, normalize, sep } from 'path';\n\n/**\n * Check if a path is contained within a base directory.\n * Prevents path traversal attacks via `..` segments or absolute paths.\n */\nfunction isContainedIn(targetPath: string, basePath: string): boolean {\n const normalizedBase = normalize(resolve(basePath));\n const normalizedTarget = normalize(resolve(targetPath));\n return normalizedTarget.startsWith(normalizedBase + sep) || normalizedTarget === normalizedBase;\n}\n\n/**\n * Validate that a relative path follows Claude Code conventions.\n * Paths must start with './' per the plugin manifest spec.\n */\nfunction isValidRelativePath(path: string): boolean {\n return path.startsWith('./');\n}\n\n/**\n * Plugin manifest types\n */\ninterface PluginManifestEntry {\n source?: string | { source: string; repo?: string };\n skills?: string[];\n /** Optional name for grouping skills (e.g., \"document-skills\") */\n name?: string;\n}\n\ninterface MarketplaceManifest {\n metadata?: { pluginRoot?: string };\n plugins?: PluginManifestEntry[];\n}\n\ninterface PluginManifest {\n skills?: string[];\n name?: string;\n}\n\n/**\n * Extract skill search directories from plugin manifests.\n * Handles both marketplace.json (multi-plugin) and plugin.json (single plugin).\n * Only resolves local paths - remote sources are skipped.\n *\n * Returns directories that CONTAIN skills (to be searched for child SKILL.md files).\n * For explicit skill paths in manifests, adds the parent directory so the\n * existing discovery loop finds them.\n */\nexport async function getPluginSkillPaths(basePath: string): Promise<string[]> {\n const searchDirs: string[] = [];\n\n // Helper: add skill paths for a plugin at a given base path\n // Only adds paths that are contained within basePath (security: prevents traversal)\n const addPluginSkillPaths = (pluginBase: string, skills?: string[]) => {\n // Validate pluginBase itself is contained\n if (!isContainedIn(pluginBase, basePath)) return;\n\n if (skills && skills.length > 0) {\n // Plugin explicitly declares skill paths - add parent dirs so existing loop finds them\n for (const skillPath of skills) {\n // Validate skill path starts with './' (per Claude Code convention)\n if (!isValidRelativePath(skillPath)) continue;\n\n const skillDir = dirname(join(pluginBase, skillPath));\n if (isContainedIn(skillDir, basePath)) {\n searchDirs.push(skillDir);\n }\n }\n }\n // Always add conventional skills/ directory for discovery\n // (deduplication happens via seenNames in discoverSkills)\n searchDirs.push(join(pluginBase, 'skills'));\n };\n\n // Try marketplace.json (multi-plugin catalog)\n try {\n const content = await readFile(join(basePath, '.claude-plugin/marketplace.json'), 'utf-8');\n const manifest: MarketplaceManifest = JSON.parse(content);\n const pluginRoot = manifest.metadata?.pluginRoot;\n\n // Validate pluginRoot starts with './' if provided (per Claude Code convention)\n const validPluginRoot = pluginRoot === undefined || isValidRelativePath(pluginRoot);\n\n if (validPluginRoot) {\n for (const plugin of manifest.plugins ?? []) {\n // Skip remote sources (object with source/repo) - only handle local string paths\n if (typeof plugin.source !== 'string' && plugin.source !== undefined) continue;\n\n // Validate source starts with './' if provided (per Claude Code convention)\n if (plugin.source !== undefined && !isValidRelativePath(plugin.source)) continue;\n\n const pluginBase = join(basePath, pluginRoot ?? '', plugin.source ?? '');\n addPluginSkillPaths(pluginBase, plugin.skills);\n }\n }\n } catch {\n // File doesn't exist or invalid JSON\n }\n\n // Try plugin.json (single plugin at root)\n try {\n const content = await readFile(join(basePath, '.claude-plugin/plugin.json'), 'utf-8');\n const manifest: PluginManifest = JSON.parse(content);\n addPluginSkillPaths(basePath, manifest.skills);\n } catch {\n // File doesn't exist or invalid JSON\n }\n\n return searchDirs;\n}\n\n/**\n * Get a map of skill directory paths to plugin names from plugin manifests.\n * This allows grouping skills by their parent plugin.\n *\n * Returns Map<AbsolutePath, PluginName>\n */\nexport async function getPluginGroupings(basePath: string): Promise<Map<string, string>> {\n const groupings = new Map<string, string>();\n\n // Try marketplace.json (multi-plugin catalog)\n try {\n const content = await readFile(join(basePath, '.claude-plugin/marketplace.json'), 'utf-8');\n const manifest: MarketplaceManifest = JSON.parse(content);\n const pluginRoot = manifest.metadata?.pluginRoot;\n\n // Validate pluginRoot starts with './' if provided (per Claude Code convention)\n const validPluginRoot = pluginRoot === undefined || isValidRelativePath(pluginRoot);\n\n if (validPluginRoot) {\n for (const plugin of manifest.plugins ?? []) {\n if (!plugin.name) continue;\n\n // Skip remote sources (object with source/repo) - only handle local string paths\n if (typeof plugin.source !== 'string' && plugin.source !== undefined) continue;\n\n // Validate source starts with './' if provided (per Claude Code convention)\n if (plugin.source !== undefined && !isValidRelativePath(plugin.source)) continue;\n\n const pluginBase = join(basePath, pluginRoot ?? '', plugin.source ?? '');\n\n // Validate pluginBase itself is contained\n if (!isContainedIn(pluginBase, basePath)) continue;\n\n if (plugin.skills && plugin.skills.length > 0) {\n for (const skillPath of plugin.skills) {\n // Validate skill path starts with './' (per Claude Code convention)\n if (!isValidRelativePath(skillPath)) continue;\n\n const skillDir = join(pluginBase, skillPath);\n if (isContainedIn(skillDir, basePath)) {\n // Store absolute path as key for reliable matching\n groupings.set(resolve(skillDir), plugin.name);\n }\n }\n }\n }\n }\n } catch {\n // File doesn't exist or invalid JSON\n }\n\n // Try plugin.json (single plugin at root)\n try {\n const content = await readFile(join(basePath, '.claude-plugin/plugin.json'), 'utf-8');\n const manifest: PluginManifest = JSON.parse(content);\n if (manifest.name && manifest.skills && manifest.skills.length > 0) {\n for (const skillPath of manifest.skills) {\n if (!isValidRelativePath(skillPath)) continue;\n const skillDir = join(basePath, skillPath);\n if (isContainedIn(skillDir, basePath)) {\n groupings.set(resolve(skillDir), manifest.name);\n }\n }\n }\n } catch {\n // File doesn't exist or invalid JSON\n }\n\n return groupings;\n}\n","import { readdir, readFile, stat } from 'fs/promises';\nimport { join, basename, dirname, resolve } from 'path';\nimport matter from 'gray-matter';\nimport type { Skill } from './types.ts';\nimport { getPluginSkillPaths, getPluginGroupings } from './plugin-manifest.ts';\n\nconst SKIP_DIRS = ['node_modules', '.git', 'dist', 'build', '__pycache__'];\n\n/**\n * Check if internal skills should be installed.\n * Internal skills are hidden by default unless INSTALL_INTERNAL_SKILLS=1 is set.\n */\nexport function shouldInstallInternalSkills(): boolean {\n const envValue = process.env.INSTALL_INTERNAL_SKILLS;\n return envValue === '1' || envValue === 'true';\n}\n\nasync function hasSkillMd(dir: string): Promise<boolean> {\n try {\n const skillPath = join(dir, 'SKILL.md');\n const stats = await stat(skillPath);\n return stats.isFile();\n } catch {\n return false;\n }\n}\n\nexport async function parseSkillMd(\n skillMdPath: string,\n options?: { includeInternal?: boolean }\n): Promise<Skill | null> {\n try {\n const content = await readFile(skillMdPath, 'utf-8');\n const { data } = matter(content);\n\n if (!data.name || !data.description) {\n return null;\n }\n\n // Ensure name and description are strings (YAML can parse numbers, booleans, etc.)\n if (typeof data.name !== 'string' || typeof data.description !== 'string') {\n return null;\n }\n\n // Skip internal skills unless:\n // 1. INSTALL_INTERNAL_SKILLS=1 is set, OR\n // 2. includeInternal option is true (e.g., when user explicitly requests a skill)\n const isInternal = data.metadata?.internal === true;\n if (isInternal && !shouldInstallInternalSkills() && !options?.includeInternal) {\n return null;\n }\n\n const rawMcpDeps = data['requires-mcp-servers'];\n return {\n name: data.name,\n description: data.description,\n path: dirname(skillMdPath),\n rawContent: content,\n metadata: data.metadata,\n requiresMcpServers: Array.isArray(rawMcpDeps) ? rawMcpDeps : undefined,\n };\n } catch {\n return null;\n }\n}\n\nasync function findSkillDirs(dir: string, depth = 0, maxDepth = 5): Promise<string[]> {\n if (depth > maxDepth) return [];\n\n try {\n const [hasSkill, entries] = await Promise.all([\n hasSkillMd(dir),\n readdir(dir, { withFileTypes: true }).catch(() => []),\n ]);\n\n const currentDir = hasSkill ? [dir] : [];\n\n // Search subdirectories in parallel\n const subDirResults = await Promise.all(\n entries\n .filter((entry) => entry.isDirectory() && !SKIP_DIRS.includes(entry.name))\n .map((entry) => findSkillDirs(join(dir, entry.name), depth + 1, maxDepth))\n );\n\n return [...currentDir, ...subDirResults.flat()];\n } catch {\n return [];\n }\n}\n\nexport interface DiscoverSkillsOptions {\n /** Include internal skills (e.g., when user explicitly requests a skill by name) */\n includeInternal?: boolean;\n /** Search all subdirectories even when a root SKILL.md exists */\n fullDepth?: boolean;\n}\n\nexport async function discoverSkills(\n basePath: string,\n subpath?: string,\n options?: DiscoverSkillsOptions\n): Promise<Skill[]> {\n const skills: Skill[] = [];\n const seenNames = new Set<string>();\n const searchPath = subpath ? join(basePath, subpath) : basePath;\n\n // Get plugin groupings to map skills to their parent plugin\n // We search for plugin definitions from the base search path\n const pluginGroupings = await getPluginGroupings(searchPath);\n\n // Helper to assign plugin name if available\n const enhanceSkill = (skill: Skill) => {\n const resolvedPath = resolve(skill.path);\n if (pluginGroupings.has(resolvedPath)) {\n skill.pluginName = pluginGroupings.get(resolvedPath);\n }\n return skill;\n };\n\n // If pointing directly at a skill, add it (and return early unless fullDepth is set)\n if (await hasSkillMd(searchPath)) {\n let skill = await parseSkillMd(join(searchPath, 'SKILL.md'), options);\n if (skill) {\n skill = enhanceSkill(skill);\n skills.push(skill);\n seenNames.add(skill.name);\n // Only return early if fullDepth is not set\n if (!options?.fullDepth) {\n return skills;\n }\n }\n }\n\n // Search common skill locations first\n const prioritySearchDirs = [\n searchPath,\n join(searchPath, 'skills'),\n join(searchPath, 'skills/.curated'),\n join(searchPath, 'skills/.experimental'),\n join(searchPath, 'skills/.system'),\n join(searchPath, '.agent/skills'),\n join(searchPath, '.agents/skills'),\n join(searchPath, '.claude/skills'),\n join(searchPath, '.cline/skills'),\n join(searchPath, '.codebuddy/skills'),\n join(searchPath, '.codex/skills'),\n join(searchPath, '.commandcode/skills'),\n join(searchPath, '.continue/skills'),\n\n join(searchPath, '.github/skills'),\n join(searchPath, '.goose/skills'),\n join(searchPath, '.iflow/skills'),\n join(searchPath, '.junie/skills'),\n join(searchPath, '.kilocode/skills'),\n join(searchPath, '.kiro/skills'),\n join(searchPath, '.mux/skills'),\n join(searchPath, '.neovate/skills'),\n join(searchPath, '.opencode/skills'),\n join(searchPath, '.openhands/skills'),\n join(searchPath, '.pi/skills'),\n join(searchPath, '.qoder/skills'),\n join(searchPath, '.roo/skills'),\n join(searchPath, '.trae/skills'),\n join(searchPath, '.windsurf/skills'),\n join(searchPath, '.zencoder/skills'),\n ];\n\n // Add skill paths declared in plugin manifests\n prioritySearchDirs.push(...(await getPluginSkillPaths(searchPath)));\n\n for (const dir of prioritySearchDirs) {\n try {\n const entries = await readdir(dir, { withFileTypes: true });\n\n for (const entry of entries) {\n if (entry.isDirectory()) {\n const skillDir = join(dir, entry.name);\n if (await hasSkillMd(skillDir)) {\n let skill = await parseSkillMd(join(skillDir, 'SKILL.md'), options);\n if (skill && !seenNames.has(skill.name)) {\n skill = enhanceSkill(skill);\n skills.push(skill);\n seenNames.add(skill.name);\n }\n }\n }\n }\n } catch {\n // Directory doesn't exist\n }\n }\n\n // Fall back to recursive search if nothing found, or if fullDepth is set\n if (skills.length === 0 || options?.fullDepth) {\n const allSkillDirs = await findSkillDirs(searchPath);\n\n for (const skillDir of allSkillDirs) {\n let skill = await parseSkillMd(join(skillDir, 'SKILL.md'), options);\n if (skill && !seenNames.has(skill.name)) {\n skill = enhanceSkill(skill);\n skills.push(skill);\n seenNames.add(skill.name);\n }\n }\n }\n\n return skills;\n}\n\nexport function getSkillDisplayName(skill: Skill): string {\n return skill.name || basename(skill.path);\n}\n\n/**\n * Filter skills based on user input (case-insensitive direct matching).\n * Multi-word skill names must be quoted on the command line.\n */\nexport function filterSkills(skills: Skill[], inputNames: string[]): Skill[] {\n const normalizedInputs = inputNames.map((n) => n.toLowerCase());\n\n return skills.filter((skill) => {\n const name = skill.name.toLowerCase();\n const displayName = getSkillDisplayName(skill).toLowerCase();\n\n return normalizedInputs.some((input) => input === name || input === displayName);\n });\n}\n","import { homedir } from 'os';\nimport { join } from 'path';\nimport { existsSync } from 'fs';\nimport { xdgConfig } from 'xdg-basedir';\nimport type { AgentConfig, AgentType } from './types.ts';\n\nconst home = homedir();\n// Use xdg-basedir (not env-paths) to match OpenCode/Amp/Goose behavior on all platforms.\nconst configHome = xdgConfig ?? join(home, '.config');\nconst codexHome = process.env.CODEX_HOME?.trim() || join(home, '.codex');\nconst claudeHome = process.env.CLAUDE_CONFIG_DIR?.trim() || join(home, '.claude');\n\nexport function getOpenClawGlobalSkillsDir(\n homeDir = home,\n pathExists: (path: string) => boolean = existsSync\n) {\n if (pathExists(join(homeDir, '.openclaw'))) {\n return join(homeDir, '.openclaw/skills');\n }\n if (pathExists(join(homeDir, '.clawdbot'))) {\n return join(homeDir, '.clawdbot/skills');\n }\n if (pathExists(join(homeDir, '.moltbot'))) {\n return join(homeDir, '.moltbot/skills');\n }\n return join(homeDir, '.openclaw/skills');\n}\n\nexport const agents: Record<AgentType, AgentConfig> = {\n amp: {\n name: 'amp',\n displayName: 'Amp',\n skillsDir: '.agents/skills',\n globalSkillsDir: join(configHome, 'agents/skills'),\n detectInstalled: async () => {\n return existsSync(join(configHome, 'amp'));\n },\n },\n antigravity: {\n name: 'antigravity',\n displayName: 'Antigravity',\n skillsDir: '.agent/skills',\n globalSkillsDir: join(home, '.gemini/antigravity/skills'),\n detectInstalled: async () => {\n return existsSync(join(home, '.gemini/antigravity'));\n },\n },\n augment: {\n name: 'augment',\n displayName: 'Augment',\n skillsDir: '.augment/skills',\n globalSkillsDir: join(home, '.augment/skills'),\n detectInstalled: async () => {\n return existsSync(join(home, '.augment'));\n },\n },\n 'claude-code': {\n name: 'claude-code',\n displayName: 'Claude Code',\n skillsDir: '.claude/skills',\n globalSkillsDir: join(claudeHome, 'skills'),\n detectInstalled: async () => {\n return existsSync(claudeHome);\n },\n },\n openclaw: {\n name: 'openclaw',\n displayName: 'OpenClaw',\n skillsDir: 'skills',\n globalSkillsDir: getOpenClawGlobalSkillsDir(),\n detectInstalled: async () => {\n return (\n existsSync(join(home, '.openclaw')) ||\n existsSync(join(home, '.clawdbot')) ||\n existsSync(join(home, '.moltbot'))\n );\n },\n },\n cline: {\n name: 'cline',\n displayName: 'Cline',\n skillsDir: '.cline/skills',\n globalSkillsDir: join(home, '.cline/skills'),\n detectInstalled: async () => {\n return existsSync(join(home, '.cline'));\n },\n },\n codebuddy: {\n name: 'codebuddy',\n displayName: 'CodeBuddy',\n skillsDir: '.codebuddy/skills',\n globalSkillsDir: join(home, '.codebuddy/skills'),\n detectInstalled: async () => {\n return existsSync(join(process.cwd(), '.codebuddy')) || existsSync(join(home, '.codebuddy'));\n },\n },\n codex: {\n name: 'codex',\n displayName: 'Codex',\n skillsDir: '.agents/skills',\n globalSkillsDir: join(codexHome, 'skills'),\n detectInstalled: async () => {\n return existsSync(codexHome) || existsSync('/etc/codex');\n },\n },\n 'command-code': {\n name: 'command-code',\n displayName: 'Command Code',\n skillsDir: '.commandcode/skills',\n globalSkillsDir: join(home, '.commandcode/skills'),\n detectInstalled: async () => {\n return existsSync(join(home, '.commandcode'));\n },\n },\n continue: {\n name: 'continue',\n displayName: 'Continue',\n skillsDir: '.continue/skills',\n globalSkillsDir: join(home, '.continue/skills'),\n detectInstalled: async () => {\n return existsSync(join(process.cwd(), '.continue')) || existsSync(join(home, '.continue'));\n },\n },\n cortex: {\n name: 'cortex',\n displayName: 'Cortex Code',\n skillsDir: '.cortex/skills',\n globalSkillsDir: join(home, '.snowflake/cortex/skills'),\n detectInstalled: async () => {\n return existsSync(join(home, '.snowflake/cortex'));\n },\n },\n crush: {\n name: 'crush',\n displayName: 'Crush',\n skillsDir: '.crush/skills',\n globalSkillsDir: join(home, '.config/crush/skills'),\n detectInstalled: async () => {\n return existsSync(join(home, '.config/crush'));\n },\n },\n cursor: {\n name: 'cursor',\n displayName: 'Cursor',\n skillsDir: '.agents/skills',\n globalSkillsDir: join(home, '.cursor/skills'),\n detectInstalled: async () => {\n return existsSync(join(home, '.cursor'));\n },\n },\n droid: {\n name: 'droid',\n displayName: 'Droid',\n skillsDir: '.factory/skills',\n globalSkillsDir: join(home, '.factory/skills'),\n detectInstalled: async () => {\n return existsSync(join(home, '.factory'));\n },\n },\n 'gemini-cli': {\n name: 'gemini-cli',\n displayName: 'Gemini CLI',\n skillsDir: '.agents/skills',\n globalSkillsDir: join(home, '.gemini/skills'),\n detectInstalled: async () => {\n return existsSync(join(home, '.gemini'));\n },\n },\n 'github-copilot': {\n name: 'github-copilot',\n displayName: 'GitHub Copilot',\n skillsDir: '.agents/skills',\n globalSkillsDir: join(home, '.copilot/skills'),\n detectInstalled: async () => {\n return existsSync(join(home, '.copilot'));\n },\n agentConfigSupport: {\n activationHint:\n 'Open Copilot Chat in your IDE and select the \"skills-mcp\" agent from the agent picker.',\n verified: true,\n },\n },\n goose: {\n name: 'goose',\n displayName: 'Goose',\n skillsDir: '.goose/skills',\n globalSkillsDir: join(configHome, 'goose/skills'),\n detectInstalled: async () => {\n return existsSync(join(configHome, 'goose'));\n },\n },\n junie: {\n name: 'junie',\n displayName: 'Junie',\n skillsDir: '.junie/skills',\n globalSkillsDir: join(home, '.junie/skills'),\n detectInstalled: async () => {\n return existsSync(join(home, '.junie'));\n },\n },\n 'iflow-cli': {\n name: 'iflow-cli',\n displayName: 'iFlow CLI',\n skillsDir: '.iflow/skills',\n globalSkillsDir: join(home, '.iflow/skills'),\n detectInstalled: async () => {\n return existsSync(join(home, '.iflow'));\n },\n },\n kilo: {\n name: 'kilo',\n displayName: 'Kilo Code',\n skillsDir: '.kilocode/skills',\n globalSkillsDir: join(home, '.kilocode/skills'),\n detectInstalled: async () => {\n return existsSync(join(home, '.kilocode'));\n },\n },\n 'kimi-cli': {\n name: 'kimi-cli',\n displayName: 'Kimi Code CLI',\n skillsDir: '.agents/skills',\n globalSkillsDir: join(home, '.config/agents/skills'),\n detectInstalled: async () => {\n return existsSync(join(home, '.kimi'));\n },\n },\n 'kiro-cli': {\n name: 'kiro-cli',\n displayName: 'Kiro CLI',\n skillsDir: '.kiro/skills',\n globalSkillsDir: join(home, '.kiro/skills'),\n detectInstalled: async () => {\n return existsSync(join(home, '.kiro'));\n },\n agentConfigSupport: {\n activationHint: 'kiro-cli chat --agent skills-mcp',\n verified: true,\n },\n },\n kode: {\n name: 'kode',\n displayName: 'Kode',\n skillsDir: '.kode/skills',\n globalSkillsDir: join(home, '.kode/skills'),\n detectInstalled: async () => {\n return existsSync(join(home, '.kode'));\n },\n },\n mcpjam: {\n name: 'mcpjam',\n displayName: 'MCPJam',\n skillsDir: '.mcpjam/skills',\n globalSkillsDir: join(home, '.mcpjam/skills'),\n detectInstalled: async () => {\n return existsSync(join(home, '.mcpjam'));\n },\n },\n 'mistral-vibe': {\n name: 'mistral-vibe',\n displayName: 'Mistral Vibe',\n skillsDir: '.vibe/skills',\n globalSkillsDir: join(home, '.vibe/skills'),\n detectInstalled: async () => {\n return existsSync(join(home, '.vibe'));\n },\n },\n mux: {\n name: 'mux',\n displayName: 'Mux',\n skillsDir: '.mux/skills',\n globalSkillsDir: join(home, '.mux/skills'),\n detectInstalled: async () => {\n return existsSync(join(home, '.mux'));\n },\n },\n opencode: {\n name: 'opencode',\n displayName: 'OpenCode',\n skillsDir: '.agents/skills',\n globalSkillsDir: join(configHome, 'opencode/skills'),\n detectInstalled: async () => {\n return existsSync(join(configHome, 'opencode'));\n },\n agentConfigSupport: {\n activationHint: 'opencode --agent skills-mcp (or type @skills-mcp inside the TUI)',\n verified: true,\n },\n },\n openhands: {\n name: 'openhands',\n displayName: 'OpenHands',\n skillsDir: '.openhands/skills',\n globalSkillsDir: join(home, '.openhands/skills'),\n detectInstalled: async () => {\n return existsSync(join(home, '.openhands'));\n },\n },\n pi: {\n name: 'pi',\n displayName: 'Pi',\n skillsDir: '.pi/skills',\n globalSkillsDir: join(home, '.pi/agent/skills'),\n detectInstalled: async () => {\n return existsSync(join(home, '.pi/agent'));\n },\n },\n qoder: {\n name: 'qoder',\n displayName: 'Qoder',\n skillsDir: '.qoder/skills',\n globalSkillsDir: join(home, '.qoder/skills'),\n detectInstalled: async () => {\n return existsSync(join(home, '.qoder'));\n },\n },\n 'qwen-code': {\n name: 'qwen-code',\n displayName: 'Qwen Code',\n skillsDir: '.qwen/skills',\n globalSkillsDir: join(home, '.qwen/skills'),\n detectInstalled: async () => {\n return existsSync(join(home, '.qwen'));\n },\n },\n replit: {\n name: 'replit',\n displayName: 'Replit',\n skillsDir: '.agents/skills',\n globalSkillsDir: join(configHome, 'agents/skills'),\n showInUniversalList: false,\n detectInstalled: async () => {\n return existsSync(join(process.cwd(), '.replit'));\n },\n },\n roo: {\n name: 'roo',\n displayName: 'Roo Code',\n skillsDir: '.roo/skills',\n globalSkillsDir: join(home, '.roo/skills'),\n detectInstalled: async () => {\n return existsSync(join(home, '.roo'));\n },\n },\n trae: {\n name: 'trae',\n displayName: 'Trae',\n skillsDir: '.trae/skills',\n globalSkillsDir: join(home, '.trae/skills'),\n detectInstalled: async () => {\n return existsSync(join(home, '.trae'));\n },\n },\n 'trae-cn': {\n name: 'trae-cn',\n displayName: 'Trae CN',\n skillsDir: '.trae/skills',\n globalSkillsDir: join(home, '.trae-cn/skills'),\n detectInstalled: async () => {\n return existsSync(join(home, '.trae-cn'));\n },\n },\n windsurf: {\n name: 'windsurf',\n displayName: 'Windsurf',\n skillsDir: '.windsurf/skills',\n globalSkillsDir: join(home, '.codeium/windsurf/skills'),\n detectInstalled: async () => {\n return existsSync(join(home, '.codeium/windsurf'));\n },\n },\n zencoder: {\n name: 'zencoder',\n displayName: 'Zencoder',\n skillsDir: '.zencoder/skills',\n globalSkillsDir: join(home, '.zencoder/skills'),\n detectInstalled: async () => {\n return existsSync(join(home, '.zencoder'));\n },\n },\n neovate: {\n name: 'neovate',\n displayName: 'Neovate',\n skillsDir: '.neovate/skills',\n globalSkillsDir: join(home, '.neovate/skills'),\n detectInstalled: async () => {\n return existsSync(join(home, '.neovate'));\n },\n },\n pochi: {\n name: 'pochi',\n displayName: 'Pochi',\n skillsDir: '.pochi/skills',\n globalSkillsDir: join(home, '.pochi/skills'),\n detectInstalled: async () => {\n return existsSync(join(home, '.pochi'));\n },\n },\n adal: {\n name: 'adal',\n displayName: 'AdaL',\n skillsDir: '.adal/skills',\n globalSkillsDir: join(home, '.adal/skills'),\n detectInstalled: async () => {\n return existsSync(join(home, '.adal'));\n },\n },\n universal: {\n name: 'universal',\n displayName: 'Universal',\n skillsDir: '.agents/skills',\n globalSkillsDir: join(configHome, 'agents/skills'),\n showInUniversalList: false,\n detectInstalled: async () => false,\n },\n};\n\nexport async function detectInstalledAgents(): Promise<AgentType[]> {\n const results = await Promise.all(\n Object.entries(agents).map(async ([type, config]) => ({\n type: type as AgentType,\n installed: await config.detectInstalled(),\n }))\n );\n return results.filter((r) => r.installed).map((r) => r.type);\n}\n\nexport function getAgentConfig(type: AgentType): AgentConfig {\n return agents[type];\n}\n\n/**\n * Returns agents that use the universal .agents/skills directory.\n * These agents share a common skill location and don't need symlinks.\n * Agents with showInUniversalList: false are excluded.\n */\nexport function getUniversalAgents(): AgentType[] {\n return (Object.entries(agents) as [AgentType, AgentConfig][])\n .filter(\n ([_, config]) => config.skillsDir === '.agents/skills' && config.showInUniversalList !== false\n )\n .map(([type]) => type);\n}\n\n/**\n * Returns agents that use agent-specific skill directories (not universal).\n * These agents need symlinks from the canonical .agents/skills location.\n */\nexport function getNonUniversalAgents(): AgentType[] {\n return (Object.entries(agents) as [AgentType, AgentConfig][])\n .filter(([_, config]) => config.skillsDir !== '.agents/skills')\n .map(([type]) => type);\n}\n\n/**\n * Check if an agent uses the universal .agents/skills directory.\n */\nexport function isUniversalAgent(type: AgentType): boolean {\n return agents[type].skillsDir === '.agents/skills';\n}\n","export const AGENTS_DIR = '.agents';\nexport const SKILLS_SUBDIR = 'skills';\nexport const UNIVERSAL_SKILLS_DIR = '.agents/skills';\n","import {\n mkdir,\n cp,\n access,\n readdir,\n symlink,\n lstat,\n rm,\n readlink,\n writeFile,\n stat,\n realpath,\n} from 'fs/promises';\nimport { join, basename, normalize, resolve, sep, relative, dirname } from 'path';\nimport { homedir, platform } from 'os';\nimport type { Skill, AgentType, MintlifySkill, RemoteSkill } from './types.ts';\nimport type { WellKnownSkill } from './providers/wellknown.ts';\nimport { agents, detectInstalledAgents, isUniversalAgent } from './agents.ts';\nimport { AGENTS_DIR, SKILLS_SUBDIR } from './constants.ts';\nimport { parseSkillMd } from './skills.ts';\n\nexport type InstallMode = 'symlink' | 'copy' | 'mcp-server';\n\ninterface InstallResult {\n success: boolean;\n path: string;\n canonicalPath?: string;\n mode: InstallMode;\n symlinkFailed?: boolean;\n error?: string;\n}\n\n/**\n * Sanitizes a filename/directory name to prevent path traversal attacks\n * and ensures it follows kebab-case convention\n * @param name - The name to sanitize\n * @returns Sanitized name safe for use in file paths\n */\nexport function sanitizeName(name: string): string {\n const sanitized = name\n .toLowerCase()\n // Replace any sequence of characters that are NOT lowercase letters (a-z),\n // digits (0-9), dots (.), or underscores (_) with a single hyphen.\n // This converts spaces, special chars, and path traversal attempts (../) into hyphens.\n .replace(/[^a-z0-9._]+/g, '-')\n // Remove leading/trailing dots and hyphens to prevent hidden files (.) and\n // ensure clean directory names. The pattern matches:\n // - ^[.\\-]+ : one or more dots or hyphens at the start\n // - [.\\-]+$ : one or more dots or hyphens at the end\n .replace(/^[.\\-]+|[.\\-]+$/g, '');\n\n // Limit to 255 chars (common filesystem limit), fallback to 'unnamed-skill' if empty\n return sanitized.substring(0, 255) || 'unnamed-skill';\n}\n\n/**\n * Validates that a path is within an expected base directory\n * @param basePath - The expected base directory\n * @param targetPath - The path to validate\n * @returns true if targetPath is within basePath\n */\nfunction isPathSafe(basePath: string, targetPath: string): boolean {\n const normalizedBase = normalize(resolve(basePath));\n const normalizedTarget = normalize(resolve(targetPath));\n\n return normalizedTarget.startsWith(normalizedBase + sep) || normalizedTarget === normalizedBase;\n}\n\nexport function getCanonicalSkillsDir(global: boolean, cwd?: string): string {\n const baseDir = global ? homedir() : cwd || process.cwd();\n return join(baseDir, AGENTS_DIR, SKILLS_SUBDIR);\n}\n\n/**\n * Gets the canonical skills directory for MCP server mode\n * Uses .agentskills/skills to match MCP server's default path\n */\nexport function getMCPCanonicalSkillsDir(global: boolean, cwd?: string): string {\n const baseDir = global ? homedir() : cwd || process.cwd();\n return join(baseDir, '.agentskills', 'skills');\n}\n\n/**\n * Gets the base directory for an agent's skills, respecting universal agents.\n * Universal agents always use the canonical directory, which prevents\n * redundant symlinks and double-listing of skills.\n */\nexport function getAgentBaseDir(agentType: AgentType, global: boolean, cwd?: string): string {\n if (isUniversalAgent(agentType)) {\n return getCanonicalSkillsDir(global, cwd);\n }\n\n const agent = agents[agentType];\n const baseDir = global ? homedir() : cwd || process.cwd();\n\n if (global) {\n if (agent.globalSkillsDir === undefined) {\n // This should be caught by callers checking support\n return join(baseDir, agent.skillsDir);\n }\n return agent.globalSkillsDir;\n }\n\n return join(baseDir, agent.skillsDir);\n}\n\nfunction resolveSymlinkTarget(linkPath: string, linkTarget: string): string {\n return resolve(dirname(linkPath), linkTarget);\n}\n\n/**\n * Cleans and recreates a directory for skill installation.\n *\n * This ensures:\n * 1. Renamed/deleted files from previous installs are removed\n * 2. Symlinks (including self-referential ones causing ELOOP) are handled\n * when canonical and agent paths resolve to the same location\n */\nasync function cleanAndCreateDirectory(path: string): Promise<void> {\n try {\n await rm(path, { recursive: true, force: true });\n } catch {\n // Ignore cleanup errors - mkdir will fail if there's a real problem\n }\n await mkdir(path, { recursive: true });\n}\n\n/**\n * Resolve a path's parent directory through symlinks, keeping the final component.\n * This handles the case where a parent directory (e.g., ~/.claude/skills) is a symlink\n * to another location (e.g., ~/.agents/skills). In that case, computing relative paths\n * from the symlink path produces broken symlinks.\n *\n * Returns the real path of the parent + the original basename.\n * If realpath fails (parent doesn't exist), returns the original resolved path.\n */\nasync function resolveParentSymlinks(path: string): Promise<string> {\n const resolved = resolve(path);\n const dir = dirname(resolved);\n const base = basename(resolved);\n try {\n const realDir = await realpath(dir);\n return join(realDir, base);\n } catch {\n return resolved;\n }\n}\n\n/**\n * Creates a symlink, handling cross-platform differences\n * Returns true if symlink was created, false if fallback to copy is needed\n */\nasync function createSymlink(target: string, linkPath: string): Promise<boolean> {\n try {\n const resolvedTarget = resolve(target);\n const resolvedLinkPath = resolve(linkPath);\n\n // Use realpath to handle cases where parent directories are symlinked.\n // This prevents deleting the canonical directory if the agent directory\n // is a symlink to the canonical location.\n const [realTarget, realLinkPath] = await Promise.all([\n realpath(resolvedTarget).catch(() => resolvedTarget),\n realpath(resolvedLinkPath).catch(() => resolvedLinkPath),\n ]);\n\n if (realTarget === realLinkPath) {\n return true;\n }\n\n // Also check with symlinks resolved in parent directories.\n // This handles cases where e.g. ~/.claude/skills is a symlink to ~/.agents/skills,\n // so ~/.claude/skills/<skill> and ~/.agents/skills/<skill> are physically the same.\n const realTargetWithParents = await resolveParentSymlinks(target);\n const realLinkPathWithParents = await resolveParentSymlinks(linkPath);\n\n if (realTargetWithParents === realLinkPathWithParents) {\n return true;\n }\n\n try {\n const stats = await lstat(linkPath);\n if (stats.isSymbolicLink()) {\n const existingTarget = await readlink(linkPath);\n if (resolveSymlinkTarget(linkPath, existingTarget) === resolvedTarget) {\n return true;\n }\n await rm(linkPath);\n } else {\n await rm(linkPath, { recursive: true });\n }\n } catch (err: unknown) {\n // ELOOP = circular symlink, ENOENT = doesn't exist\n // For ELOOP, try to remove the broken symlink\n if (err && typeof err === 'object' && 'code' in err && err.code === 'ELOOP') {\n try {\n await rm(linkPath, { force: true });\n } catch {\n // If we can't remove it, symlink creation will fail and trigger copy fallback\n }\n }\n // For ENOENT or other errors, continue to symlink creation\n }\n\n const linkDir = dirname(linkPath);\n await mkdir(linkDir, { recursive: true });\n\n // Use the real (symlink-resolved) parent directory for computing the relative path.\n // This ensures the symlink target is correct even when the link's parent dir is a symlink.\n const realLinkDir = await resolveParentSymlinks(linkDir);\n const relativePath = relative(realLinkDir, target);\n const symlinkType = platform() === 'win32' ? 'junction' : undefined;\n\n await symlink(relativePath, linkPath, symlinkType);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function installSkillForAgent(\n skill: Skill,\n agentType: AgentType,\n options: { global?: boolean; cwd?: string; mode?: InstallMode } = {}\n): Promise<InstallResult> {\n const agent = agents[agentType];\n const isGlobal = options.global ?? false;\n const cwd = options.cwd || process.cwd();\n\n // Check if agent supports global installation\n if (isGlobal && agent.globalSkillsDir === undefined) {\n return {\n success: false,\n path: '',\n mode: options.mode ?? 'symlink',\n error: `${agent.displayName} does not support global skill installation`,\n };\n }\n\n // Sanitize skill name to prevent directory traversal\n const rawSkillName = skill.name || basename(skill.path);\n const skillName = sanitizeName(rawSkillName);\n\n const installMode = options.mode ?? 'symlink';\n\n // Canonical location: use MCP path for MCP server mode, standard path otherwise\n const canonicalBase =\n installMode === 'mcp-server'\n ? getMCPCanonicalSkillsDir(isGlobal, cwd)\n : getCanonicalSkillsDir(isGlobal, cwd);\n const canonicalDir = join(canonicalBase, skillName);\n\n // Agent-specific location (for symlink)\n const agentBase = getAgentBaseDir(agentType, isGlobal, cwd);\n const agentDir = join(agentBase, skillName);\n\n // Validate paths\n if (!isPathSafe(canonicalBase, canonicalDir)) {\n return {\n success: false,\n path: agentDir,\n mode: installMode,\n error: 'Invalid skill name: potential path traversal detected',\n };\n }\n\n if (!isPathSafe(agentBase, agentDir)) {\n return {\n success: false,\n path: agentDir,\n mode: installMode,\n error: 'Invalid skill name: potential path traversal detected',\n };\n }\n\n try {\n // MCP server mode: only write to canonical location, no per-agent symlink/copy\n if (installMode === 'mcp-server') {\n await cleanAndCreateDirectory(canonicalDir);\n await copyDirectory(skill.path, canonicalDir);\n return {\n success: true,\n path: canonicalDir,\n canonicalPath: canonicalDir,\n mode: 'mcp-server',\n };\n }\n\n // For copy mode, skip canonical directory and copy directly to agent location\n if (installMode === 'copy') {\n await cleanAndCreateDirectory(agentDir);\n await copyDirectory(skill.path, agentDir);\n\n return {\n success: true,\n path: agentDir,\n mode: 'copy',\n };\n }\n\n // Symlink mode: copy to canonical location and symlink to agent location\n await cleanAndCreateDirectory(canonicalDir);\n await copyDirectory(skill.path, canonicalDir);\n\n // For universal agents with global install, the skill is already in the canonical\n // ~/.agents/skills directory. Skip creating a symlink to the agent-specific global dir\n // (e.g. ~/.copilot/skills) to avoid duplicates.\n if (isGlobal && isUniversalAgent(agentType)) {\n return {\n success: true,\n path: canonicalDir,\n canonicalPath: canonicalDir,\n mode: 'symlink',\n };\n }\n\n const symlinkCreated = await createSymlink(canonicalDir, agentDir);\n\n if (!symlinkCreated) {\n // Symlink failed, fall back to copy\n await cleanAndCreateDirectory(agentDir);\n await copyDirectory(skill.path, agentDir);\n\n return {\n success: true,\n path: agentDir,\n canonicalPath: canonicalDir,\n mode: 'symlink',\n symlinkFailed: true,\n };\n }\n\n return {\n success: true,\n path: agentDir,\n canonicalPath: canonicalDir,\n mode: 'symlink',\n };\n } catch (error) {\n return {\n success: false,\n path: agentDir,\n mode: installMode,\n error: error instanceof Error ? error.message : 'Unknown error',\n };\n }\n}\n\nconst EXCLUDE_FILES = new Set(['metadata.json']);\nconst EXCLUDE_DIRS = new Set(['.git']);\n\nconst isExcluded = (name: string, isDirectory: boolean = false): boolean => {\n if (EXCLUDE_FILES.has(name)) return true;\n if (name.startsWith('_')) return true;\n if (isDirectory && EXCLUDE_DIRS.has(name)) return true;\n return false;\n};\n\nasync function copyDirectory(src: string, dest: string): Promise<void> {\n await mkdir(dest, { recursive: true });\n\n const entries = await readdir(src, { withFileTypes: true });\n\n // Copy files and directories in parallel\n await Promise.all(\n entries\n .filter((entry) => !isExcluded(entry.name, entry.isDirectory()))\n .map(async (entry) => {\n const srcPath = join(src, entry.name);\n const destPath = join(dest, entry.name);\n\n if (entry.isDirectory()) {\n await copyDirectory(srcPath, destPath);\n } else {\n await cp(srcPath, destPath, {\n // If the file is a symlink to elsewhere in a remote skill, it may not\n // resolve correctly once it has been copied to the local location.\n // `dereference: true` tells Node to copy the file instead of copying\n // the symlink. `recursive: true` handles symlinks pointing to directories.\n dereference: true,\n recursive: true,\n });\n }\n })\n );\n}\n\nexport async function isSkillInstalled(\n skillName: string,\n agentType: AgentType,\n options: { global?: boolean; cwd?: string } = {}\n): Promise<boolean> {\n const agent = agents[agentType];\n const sanitized = sanitizeName(skillName);\n\n // Agent doesn't support global installation\n if (options.global && agent.globalSkillsDir === undefined) {\n return false;\n }\n\n const targetBase = options.global\n ? agent.globalSkillsDir!\n : join(options.cwd || process.cwd(), agent.skillsDir);\n\n const skillDir = join(targetBase, sanitized);\n\n if (!isPathSafe(targetBase, skillDir)) {\n return false;\n }\n\n try {\n await access(skillDir);\n return true;\n } catch {\n return false;\n }\n}\n\nexport function getInstallPath(\n skillName: string,\n agentType: AgentType,\n options: { global?: boolean; cwd?: string } = {}\n): string {\n const agent = agents[agentType];\n const cwd = options.cwd || process.cwd();\n const sanitized = sanitizeName(skillName);\n\n const targetBase = getAgentBaseDir(agentType, options.global ?? false, options.cwd);\n const installPath = join(targetBase, sanitized);\n\n if (!isPathSafe(targetBase, installPath)) {\n throw new Error('Invalid skill name: potential path traversal detected');\n }\n\n return installPath;\n}\n\n/**\n * Gets the canonical .agents/skills/<skill> path\n */\nexport function getCanonicalPath(\n skillName: string,\n options: { global?: boolean; cwd?: string } = {}\n): string {\n const sanitized = sanitizeName(skillName);\n const canonicalBase = getCanonicalSkillsDir(options.global ?? false, options.cwd);\n const canonicalPath = join(canonicalBase, sanitized);\n\n if (!isPathSafe(canonicalBase, canonicalPath)) {\n throw new Error('Invalid skill name: potential path traversal detected');\n }\n\n return canonicalPath;\n}\n\n/**\n * Install a Mintlify skill from a direct URL\n * The skill name is derived from the mintlify-proj frontmatter\n * Supports symlink mode (writes to canonical location and symlinks to agent dirs)\n * or copy mode (writes directly to each agent dir).\n * @deprecated Use installRemoteSkillForAgent instead\n */\nexport async function installMintlifySkillForAgent(\n skill: MintlifySkill,\n agentType: AgentType,\n options: { global?: boolean; cwd?: string; mode?: InstallMode } = {}\n): Promise<InstallResult> {\n const agent = agents[agentType];\n const isGlobal = options.global ?? false;\n const cwd = options.cwd || process.cwd();\n const installMode = options.mode ?? 'symlink';\n\n // Check if agent supports global installation\n if (isGlobal && agent.globalSkillsDir === undefined) {\n return {\n success: false,\n path: '',\n mode: installMode,\n error: `${agent.displayName} does not support global skill installation`,\n };\n }\n\n // Use mintlify-proj as the skill directory name (e.g., \"bun.com\")\n const skillName = sanitizeName(skill.mintlifySite);\n\n // Canonical location: use MCP path for MCP server mode, standard path otherwise\n const canonicalBase =\n installMode === 'mcp-server'\n ? getMCPCanonicalSkillsDir(isGlobal, cwd)\n : getCanonicalSkillsDir(isGlobal, cwd);\n const canonicalDir = join(canonicalBase, skillName);\n\n // Agent-specific location (for symlink)\n const agentBase = isGlobal ? agent.globalSkillsDir! : join(cwd, agent.skillsDir);\n const agentDir = join(agentBase, skillName);\n\n // Validate paths\n if (!isPathSafe(canonicalBase, canonicalDir)) {\n return {\n success: false,\n path: agentDir,\n mode: installMode,\n error: 'Invalid skill name: potential path traversal detected',\n };\n }\n\n if (!isPathSafe(agentBase, agentDir)) {\n return {\n success: false,\n path: agentDir,\n mode: installMode,\n error: 'Invalid skill name: potential path traversal detected',\n };\n }\n\n try {\n // MCP server mode: only write to canonical location, no per-agent symlink/copy\n if (installMode === 'mcp-server') {\n await cleanAndCreateDirectory(canonicalDir);\n const skillMdPath = join(canonicalDir, 'SKILL.md');\n await writeFile(skillMdPath, skill.content, 'utf-8');\n return {\n success: true,\n path: canonicalDir,\n canonicalPath: canonicalDir,\n mode: 'mcp-server',\n };\n }\n\n // For copy mode, write directly to agent location\n if (installMode === 'copy') {\n await cleanAndCreateDirectory(agentDir);\n const skillMdPath = join(agentDir, 'SKILL.md');\n await writeFile(skillMdPath, skill.content, 'utf-8');\n\n return {\n success: true,\n path: agentDir,\n mode: 'copy',\n };\n }\n\n // Symlink mode: write to canonical location and symlink to agent location\n await cleanAndCreateDirectory(canonicalDir);\n const skillMdPath = join(canonicalDir, 'SKILL.md');\n await writeFile(skillMdPath, skill.content, 'utf-8');\n\n // For universal agents with global install, skip creating agent-specific symlink\n if (isGlobal && isUniversalAgent(agentType)) {\n return {\n success: true,\n path: canonicalDir,\n canonicalPath: canonicalDir,\n mode: 'symlink',\n };\n }\n\n const symlinkCreated = await createSymlink(canonicalDir, agentDir);\n\n if (!symlinkCreated) {\n // Symlink failed, fall back to copy\n await cleanAndCreateDirectory(agentDir);\n const agentSkillMdPath = join(agentDir, 'SKILL.md');\n await writeFile(agentSkillMdPath, skill.content, 'utf-8');\n\n return {\n success: true,\n path: agentDir,\n canonicalPath: canonicalDir,\n mode: 'symlink',\n symlinkFailed: true,\n };\n }\n\n return {\n success: true,\n path: agentDir,\n canonicalPath: canonicalDir,\n mode: 'symlink',\n };\n } catch (error) {\n return {\n success: false,\n path: agentDir,\n mode: installMode,\n error: error instanceof Error ? error.message : 'Unknown error',\n };\n }\n}\n\n/**\n * Install a remote skill from any host provider.\n * The skill directory name is derived from the installName field.\n * Supports symlink mode (writes to canonical location and symlinks to agent dirs)\n * or copy mode (writes directly to each agent dir).\n */\nexport async function installRemoteSkillForAgent(\n skill: RemoteSkill,\n agentType: AgentType,\n options: { global?: boolean; cwd?: string; mode?: InstallMode } = {}\n): Promise<InstallResult> {\n const agent = agents[agentType];\n const isGlobal = options.global ?? false;\n const cwd = options.cwd || process.cwd();\n const installMode = options.mode ?? 'symlink';\n\n // Check if agent supports global installation\n if (isGlobal && agent.globalSkillsDir === undefined) {\n return {\n success: false,\n path: '',\n mode: installMode,\n error: `${agent.displayName} does not support global skill installation`,\n };\n }\n\n // Use installName as the skill directory name\n const skillName = sanitizeName(skill.installName);\n\n // Canonical location: use MCP path for MCP server mode, standard path otherwise\n const canonicalBase =\n installMode === 'mcp-server'\n ? getMCPCanonicalSkillsDir(isGlobal, cwd)\n : getCanonicalSkillsDir(isGlobal, cwd);\n const canonicalDir = join(canonicalBase, skillName);\n\n // Agent-specific location (for symlink)\n const agentBase = getAgentBaseDir(agentType, isGlobal, cwd);\n const agentDir = join(agentBase, skillName);\n\n // Validate paths\n if (!isPathSafe(canonicalBase, canonicalDir)) {\n return {\n success: false,\n path: agentDir,\n mode: installMode,\n error: 'Invalid skill name: potential path traversal detected',\n };\n }\n\n if (!isPathSafe(agentBase, agentDir)) {\n return {\n success: false,\n path: agentDir,\n mode: installMode,\n error: 'Invalid skill name: potential path traversal detected',\n };\n }\n\n try {\n // MCP server mode: only write to canonical location, no per-agent symlink/copy\n if (installMode === 'mcp-server') {\n await cleanAndCreateDirectory(canonicalDir);\n const skillMdPath = join(canonicalDir, 'SKILL.md');\n await writeFile(skillMdPath, skill.content, 'utf-8');\n return {\n success: true,\n path: canonicalDir,\n canonicalPath: canonicalDir,\n mode: 'mcp-server',\n };\n }\n\n // For copy mode, write directly to agent location\n if (installMode === 'copy') {\n await cleanAndCreateDirectory(agentDir);\n const skillMdPath = join(agentDir, 'SKILL.md');\n await writeFile(skillMdPath, skill.content, 'utf-8');\n\n return {\n success: true,\n path: agentDir,\n mode: 'copy',\n };\n }\n\n // Symlink mode: write to canonical location and symlink to agent location\n await cleanAndCreateDirectory(canonicalDir);\n const skillMdPath = join(canonicalDir, 'SKILL.md');\n await writeFile(skillMdPath, skill.content, 'utf-8');\n\n // For universal agents with global install, skip creating agent-specific symlink\n if (isGlobal && isUniversalAgent(agentType)) {\n return {\n success: true,\n path: canonicalDir,\n canonicalPath: canonicalDir,\n mode: 'symlink',\n };\n }\n\n const symlinkCreated = await createSymlink(canonicalDir, agentDir);\n\n if (!symlinkCreated) {\n // Symlink failed, fall back to copy\n await cleanAndCreateDirectory(agentDir);\n const agentSkillMdPath = join(agentDir, 'SKILL.md');\n await writeFile(agentSkillMdPath, skill.content, 'utf-8');\n\n return {\n success: true,\n path: agentDir,\n canonicalPath: canonicalDir,\n mode: 'symlink',\n symlinkFailed: true,\n };\n }\n\n return {\n success: true,\n path: agentDir,\n canonicalPath: canonicalDir,\n mode: 'symlink',\n };\n } catch (error) {\n return {\n success: false,\n path: agentDir,\n mode: installMode,\n error: error instanceof Error ? error.message : 'Unknown error',\n };\n }\n}\n\n/**\n * Install a well-known skill with multiple files.\n * The skill directory name is derived from the installName field.\n * All files from the skill's files map are written to the installation directory.\n * Supports symlink mode (writes to canonical location and symlinks to agent dirs)\n * or copy mode (writes directly to each agent dir).\n */\nexport async function installWellKnownSkillForAgent(\n skill: WellKnownSkill,\n agentType: AgentType,\n options: { global?: boolean; cwd?: string; mode?: InstallMode } = {}\n): Promise<InstallResult> {\n const agent = agents[agentType];\n const isGlobal = options.global ?? false;\n const cwd = options.cwd || process.cwd();\n const installMode = options.mode ?? 'symlink';\n\n // Check if agent supports global installation\n if (isGlobal && agent.globalSkillsDir === undefined) {\n return {\n success: false,\n path: '',\n mode: installMode,\n error: `${agent.displayName} does not support global skill installation`,\n };\n }\n\n // Use installName as the skill directory name\n const skillName = sanitizeName(skill.installName);\n\n // Canonical location: use MCP path for MCP server mode, standard path otherwise\n const canonicalBase =\n installMode === 'mcp-server'\n ? getMCPCanonicalSkillsDir(isGlobal, cwd)\n : getCanonicalSkillsDir(isGlobal, cwd);\n const canonicalDir = join(canonicalBase, skillName);\n\n // Agent-specific location (for symlink)\n const agentBase = getAgentBaseDir(agentType, isGlobal, cwd);\n const agentDir = join(agentBase, skillName);\n\n // Validate paths\n if (!isPathSafe(canonicalBase, canonicalDir)) {\n return {\n success: false,\n path: agentDir,\n mode: installMode,\n error: 'Invalid skill name: potential path traversal detected',\n };\n }\n\n if (!isPathSafe(agentBase, agentDir)) {\n return {\n success: false,\n path: agentDir,\n mode: installMode,\n error: 'Invalid skill name: potential path traversal detected',\n };\n }\n\n /**\n * Write all skill files to a directory (assumes directory already exists)\n */\n async function writeSkillFiles(targetDir: string): Promise<void> {\n for (const [filePath, content] of skill.files) {\n // Validate file path doesn't escape the target directory\n const fullPath = join(targetDir, filePath);\n if (!isPathSafe(targetDir, fullPath)) {\n continue; // Skip files that would escape the directory\n }\n\n // Create parent directories if needed\n const parentDir = dirname(fullPath);\n if (parentDir !== targetDir) {\n await mkdir(parentDir, { recursive: true });\n }\n\n await writeFile(fullPath, content, 'utf-8');\n }\n }\n\n try {\n // MCP server mode: only write to canonical location, no per-agent symlink/copy\n if (installMode === 'mcp-server') {\n await cleanAndCreateDirectory(canonicalDir);\n await writeSkillFiles(canonicalDir);\n return {\n success: true,\n path: canonicalDir,\n canonicalPath: canonicalDir,\n mode: 'mcp-server',\n };\n }\n\n // For copy mode, write directly to agent location\n if (installMode === 'copy') {\n await cleanAndCreateDirectory(agentDir);\n await writeSkillFiles(agentDir);\n\n return {\n success: true,\n path: agentDir,\n mode: 'copy',\n };\n }\n\n // Symlink mode: write to canonical location and symlink to agent location\n await cleanAndCreateDirectory(canonicalDir);\n await writeSkillFiles(canonicalDir);\n\n // For universal agents with global install, skip creating agent-specific symlink\n if (isGlobal && isUniversalAgent(agentType)) {\n return {\n success: true,\n path: canonicalDir,\n canonicalPath: canonicalDir,\n mode: 'symlink',\n };\n }\n\n const symlinkCreated = await createSymlink(canonicalDir, agentDir);\n\n if (!symlinkCreated) {\n // Symlink failed, fall back to copy\n await cleanAndCreateDirectory(agentDir);\n await writeSkillFiles(agentDir);\n\n return {\n success: true,\n path: agentDir,\n canonicalPath: canonicalDir,\n mode: 'symlink',\n symlinkFailed: true,\n };\n }\n\n return {\n success: true,\n path: agentDir,\n canonicalPath: canonicalDir,\n mode: 'symlink',\n };\n } catch (error) {\n return {\n success: false,\n path: agentDir,\n mode: installMode,\n error: error instanceof Error ? error.message : 'Unknown error',\n };\n }\n}\n\nexport interface InstalledSkill {\n name: string;\n description: string;\n path: string;\n canonicalPath: string;\n scope: 'project' | 'global';\n agents: AgentType[];\n}\n\n/**\n * Lists all installed skills from canonical locations\n * @param options - Options for listing skills\n * @returns Array of installed skills with metadata\n */\nexport async function listInstalledSkills(\n options: {\n global?: boolean;\n cwd?: string;\n agentFilter?: AgentType[];\n } = {}\n): Promise<InstalledSkill[]> {\n const cwd = options.cwd || process.cwd();\n // Use a Map to deduplicate skills by scope:name\n const skillsMap: Map<string, InstalledSkill> = new Map();\n const scopes: Array<{ global: boolean; path: string; agentType?: AgentType }> = [];\n\n // Detect which agents are actually installed\n const detectedAgents = await detectInstalledAgents();\n const agentFilter = options.agentFilter;\n const agentsToCheck = agentFilter\n ? detectedAgents.filter((a) => agentFilter.includes(a))\n : detectedAgents;\n\n // Determine which scopes to scan\n const scopeTypes: Array<{ global: boolean }> = [];\n if (options.global === undefined) {\n scopeTypes.push({ global: false }, { global: true });\n } else {\n scopeTypes.push({ global: options.global });\n }\n\n // Build list of directories to scan: canonical + each installed agent's directory\n //\n // Scanning workflow:\n //\n // detectInstalledAgents()\n // │\n // ▼\n // for each scope (project / global)\n // │\n // ├──▶ scan canonical dir ──▶ .agents/skills, ~/.agents/skills\n // │\n // ├──▶ scan each installed agent's dir ──▶ .cursor/skills, .claude/skills, ...\n // │\n // ▼\n // deduplicate by skill name\n //\n // Trade-off: More readdir() calls, but most non-existent dirs fail fast.\n // Skills in agent-specific dirs skip the expensive \"check all agents\" loop.\n //\n for (const { global: isGlobal } of scopeTypes) {\n // Add canonical directory\n scopes.push({ global: isGlobal, path: getCanonicalSkillsDir(isGlobal, cwd) });\n\n // Add each installed agent's skills directory\n for (const agentType of agentsToCheck) {\n const agent = agents[agentType];\n if (isGlobal && agent.globalSkillsDir === undefined) {\n continue;\n }\n const agentDir = isGlobal ? agent.globalSkillsDir! : join(cwd, agent.skillsDir);\n // Avoid duplicate paths\n if (!scopes.some((s) => s.path === agentDir && s.global === isGlobal)) {\n scopes.push({ global: isGlobal, path: agentDir, agentType });\n }\n }\n }\n\n for (const scope of scopes) {\n try {\n const entries = await readdir(scope.path, { withFileTypes: true });\n\n for (const entry of entries) {\n if (!entry.isDirectory()) {\n continue;\n }\n\n const skillDir = join(scope.path, entry.name);\n const skillMdPath = join(skillDir, 'SKILL.md');\n\n // Check if SKILL.md exists\n try {\n await stat(skillMdPath);\n } catch {\n // SKILL.md doesn't exist, skip this directory\n continue;\n }\n\n // Parse the skill\n const skill = await parseSkillMd(skillMdPath);\n if (!skill) {\n continue;\n }\n\n const scopeKey = scope.global ? 'global' : 'project';\n const skillKey = `${scopeKey}:${skill.name}`;\n\n // If scanning an agent-specific directory, attribute directly to that agent\n if (scope.agentType) {\n if (skillsMap.has(skillKey)) {\n const existing = skillsMap.get(skillKey)!;\n if (!existing.agents.includes(scope.agentType)) {\n existing.agents.push(scope.agentType);\n }\n } else {\n skillsMap.set(skillKey, {\n name: skill.name,\n description: skill.description,\n path: skillDir,\n canonicalPath: skillDir,\n scope: scopeKey,\n agents: [scope.agentType],\n });\n }\n continue;\n }\n\n // For canonical directory, check which agents have this skill\n const sanitizedSkillName = sanitizeName(skill.name);\n const installedAgents: AgentType[] = [];\n\n for (const agentType of agentsToCheck) {\n const agent = agents[agentType];\n\n if (scope.global && agent.globalSkillsDir === undefined) {\n continue;\n }\n\n const agentBase = scope.global ? agent.globalSkillsDir! : join(cwd, agent.skillsDir);\n let found = false;\n\n // Try exact directory name matches\n const possibleNames = Array.from(\n new Set([\n entry.name,\n sanitizedSkillName,\n skill.name\n .toLowerCase()\n .replace(/\\s+/g, '-')\n .replace(/[\\/\\\\:\\0]/g, ''),\n ])\n );\n\n for (const possibleName of possibleNames) {\n const agentSkillDir = join(agentBase, possibleName);\n if (!isPathSafe(agentBase, agentSkillDir)) continue;\n\n try {\n await access(agentSkillDir);\n found = true;\n break;\n } catch {\n // Try next name\n }\n }\n\n // Fallback: scan all directories and check SKILL.md files\n // Handles cases where directory names don't match (e.g., \"git-review\" vs \"Git Review Before Commit\")\n if (!found) {\n try {\n const agentEntries = await readdir(agentBase, { withFileTypes: true });\n for (const agentEntry of agentEntries) {\n if (!agentEntry.isDirectory()) continue;\n\n const candidateDir = join(agentBase, agentEntry.name);\n if (!isPathSafe(agentBase, candidateDir)) continue;\n\n try {\n const candidateSkillMd = join(candidateDir, 'SKILL.md');\n await stat(candidateSkillMd);\n const candidateSkill = await parseSkillMd(candidateSkillMd);\n if (candidateSkill && candidateSkill.name === skill.name) {\n found = true;\n break;\n }\n } catch {\n // Not a valid skill directory\n }\n }\n } catch {\n // Agent base directory doesn't exist\n }\n }\n\n if (found) {\n installedAgents.push(agentType);\n }\n }\n\n if (skillsMap.has(skillKey)) {\n // Merge agents\n const existing = skillsMap.get(skillKey)!;\n for (const agent of installedAgents) {\n if (!existing.agents.includes(agent)) {\n existing.agents.push(agent);\n }\n }\n } else {\n skillsMap.set(skillKey, {\n name: skill.name,\n description: skill.description,\n path: skillDir,\n canonicalPath: skillDir,\n scope: scopeKey,\n agents: installedAgents,\n });\n }\n }\n } catch {\n // Directory doesn't exist, skip\n }\n }\n\n return Array.from(skillsMap.values());\n}\n","const TELEMETRY_URL = 'https://add-skill.vercel.sh/t';\nconst AUDIT_URL = 'https://add-skill.vercel.sh/audit';\n\ninterface InstallTelemetryData {\n event: 'install';\n source: string;\n skills: string;\n agents: string;\n global?: '1';\n skillFiles?: string; // JSON stringified { skillName: relativePath }\n /**\n * Source type for different hosts:\n * - 'github': GitHub repository (default, uses raw.githubusercontent.com)\n * - 'raw': Direct URL to SKILL.md (generic raw URL)\n * - Provider IDs like 'mintlify', 'huggingface', etc.\n */\n sourceType?: string;\n}\n\ninterface RemoveTelemetryData {\n event: 'remove';\n source?: string;\n skills: string;\n agents: string;\n global?: '1';\n sourceType?: string;\n}\n\ninterface CheckTelemetryData {\n event: 'check';\n skillCount: string;\n updatesAvailable: string;\n}\n\ninterface UpdateTelemetryData {\n event: 'update';\n skillCount: string;\n successCount: string;\n failCount: string;\n}\n\ninterface FindTelemetryData {\n event: 'find';\n query: string;\n resultCount: string;\n interactive?: '1';\n}\n\ninterface SyncTelemetryData {\n event: 'experimental_sync';\n skillCount: string;\n successCount: string;\n agents: string;\n}\n\ntype TelemetryData =\n | InstallTelemetryData\n | RemoveTelemetryData\n | CheckTelemetryData\n | UpdateTelemetryData\n | FindTelemetryData\n | SyncTelemetryData;\n\nlet cliVersion: string | null = null;\n\nfunction isCI(): boolean {\n return !!(\n process.env.CI ||\n process.env.GITHUB_ACTIONS ||\n process.env.GITLAB_CI ||\n process.env.CIRCLECI ||\n process.env.TRAVIS ||\n process.env.BUILDKITE ||\n process.env.JENKINS_URL ||\n process.env.TEAMCITY_VERSION\n );\n}\n\nfunction isEnabled(): boolean {\n return !process.env.DISABLE_TELEMETRY && !process.env.DO_NOT_TRACK;\n}\n\nexport function setVersion(version: string): void {\n cliVersion = version;\n}\n\n// ─── Security audit data ───\n\nexport interface PartnerAudit {\n risk: 'safe' | 'low' | 'medium' | 'high' | 'critical' | 'unknown';\n alerts?: number;\n score?: number;\n analyzedAt: string;\n}\n\nexport type SkillAuditData = Record<string, PartnerAudit>;\nexport type AuditResponse = Record<string, SkillAuditData>;\n\n/**\n * Fetch security audit results for skills from the audit API.\n * Returns null on any error or timeout — never blocks installation.\n */\nexport async function fetchAuditData(\n source: string,\n skillSlugs: string[],\n timeoutMs = 3000\n): Promise<AuditResponse | null> {\n if (skillSlugs.length === 0) return null;\n\n try {\n const params = new URLSearchParams({\n source,\n skills: skillSlugs.join(','),\n });\n\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), timeoutMs);\n\n const response = await fetch(`${AUDIT_URL}?${params.toString()}`, {\n signal: controller.signal,\n });\n clearTimeout(timeout);\n\n if (!response.ok) return null;\n return (await response.json()) as AuditResponse;\n } catch {\n return null;\n }\n}\n\nexport function track(data: TelemetryData): void {\n if (!isEnabled()) return;\n\n try {\n const params = new URLSearchParams();\n\n // Add version\n if (cliVersion) {\n params.set('v', cliVersion);\n }\n\n // Add CI flag if running in CI\n if (isCI()) {\n params.set('ci', '1');\n }\n\n // Add event data\n for (const [key, value] of Object.entries(data)) {\n if (value !== undefined && value !== null) {\n params.set(key, String(value));\n }\n }\n\n // Fire and forget - don't await, silently ignore errors\n fetch(`${TELEMETRY_URL}?${params.toString()}`).catch(() => {});\n } catch {\n // Silently fail - telemetry should never break the CLI\n }\n}\n","import type { HostProvider, ProviderRegistry } from './types.ts';\n\nclass ProviderRegistryImpl implements ProviderRegistry {\n private providers: HostProvider[] = [];\n\n register(provider: HostProvider): void {\n // Check for duplicate IDs\n if (this.providers.some((p) => p.id === provider.id)) {\n throw new Error(`Provider with id \"${provider.id}\" already registered`);\n }\n this.providers.push(provider);\n }\n\n findProvider(url: string): HostProvider | null {\n for (const provider of this.providers) {\n const match = provider.match(url);\n if (match.matches) {\n return provider;\n }\n }\n return null;\n }\n\n getProviders(): HostProvider[] {\n return [...this.providers];\n }\n}\n\n// Singleton registry instance\nexport const registry = new ProviderRegistryImpl();\n\n/**\n * Register a provider with the global registry.\n */\nexport function registerProvider(provider: HostProvider): void {\n registry.register(provider);\n}\n\n/**\n * Find a provider that matches the given URL.\n */\nexport function findProvider(url: string): HostProvider | null {\n return registry.findProvider(url);\n}\n\n/**\n * Get all registered providers.\n */\nexport function getProviders(): HostProvider[] {\n return registry.getProviders();\n}\n","import matter from 'gray-matter';\nimport type { HostProvider, ProviderMatch, RemoteSkill } from './types.ts';\n\n/**\n * Mintlify-hosted skills provider.\n *\n * Mintlify skills are identified by:\n * 1. URL ending in /skill.md (case insensitive)\n * 2. Frontmatter containing `metadata.mintlify-proj`\n *\n * The `mintlify-proj` value is used as:\n * - The skill's installation directory name\n * - Part of the source identifier for telemetry\n *\n * Example URL: https://mintlify.com/docs/skill.md\n * Example frontmatter:\n * ```yaml\n * name: Mintlify Development\n * description: Build documentation with Mintlify\n * metadata:\n * mintlify-proj: mintlify.com\n * ```\n */\nexport class MintlifyProvider implements HostProvider {\n readonly id = 'mintlify';\n readonly displayName = 'Mintlify';\n\n match(url: string): ProviderMatch {\n // Must be a valid HTTP(S) URL\n if (!url.startsWith('http://') && !url.startsWith('https://')) {\n return { matches: false };\n }\n\n // Must end with /skill.md (case insensitive)\n if (!url.toLowerCase().endsWith('/skill.md')) {\n return { matches: false };\n }\n\n // Exclude GitHub and GitLab - they have their own handling\n if (url.includes('github.com') || url.includes('gitlab.com')) {\n return { matches: false };\n }\n\n // Exclude HuggingFace - it has its own provider\n if (url.includes('huggingface.co')) {\n return { matches: false };\n }\n\n return { matches: true };\n }\n\n async fetchSkill(url: string): Promise<RemoteSkill | null> {\n try {\n const response = await fetch(url, { signal: AbortSignal.timeout(30000) });\n\n if (!response.ok) {\n return null;\n }\n\n const content = await response.text();\n const { data } = matter(content);\n\n // Must have mintlify-proj in metadata\n const mintlifySite = data.metadata?.['mintlify-proj'];\n if (!mintlifySite) {\n return null;\n }\n\n // Must have name and description\n if (!data.name || !data.description) {\n return null;\n }\n\n return {\n name: data.name,\n description: data.description,\n content,\n installName: mintlifySite,\n sourceUrl: url,\n metadata: data.metadata,\n };\n } catch {\n return null;\n }\n }\n\n toRawUrl(url: string): string {\n // Mintlify URLs are already direct content URLs\n return url;\n }\n\n getSourceIdentifier(url: string): string {\n // For Mintlify, we use \"mintlify/com\" as the identifier\n // This groups all Mintlify skills together under a single \"repo\"\n // The individual skill name (mintlify-proj) serves as the skill identifier\n // Leaderboard URL: /mintlify/com/{skill-name}\n return 'mintlify/com';\n }\n}\n\nexport const mintlifyProvider = new MintlifyProvider();\n","import matter from 'gray-matter';\nimport type { HostProvider, ProviderMatch, RemoteSkill } from './types.ts';\n\n/**\n * HuggingFace Spaces skills provider.\n *\n * HuggingFace skills are hosted in HuggingFace Spaces repositories.\n *\n * URL formats supported:\n * - https://huggingface.co/spaces/{owner}/{repo}/blob/main/SKILL.md (web view)\n * - https://huggingface.co/spaces/{owner}/{repo}/raw/main/SKILL.md (raw content)\n *\n * The source identifier is \"huggingface/{owner}/{repo}\".\n * The install name defaults to the repo name, but can be overridden with\n * frontmatter `metadata.install-name`.\n */\nexport class HuggingFaceProvider implements HostProvider {\n readonly id = 'huggingface';\n readonly displayName = 'HuggingFace';\n\n private readonly HOST = 'huggingface.co';\n\n match(url: string): ProviderMatch {\n // Must be a valid HTTP(S) URL\n if (!url.startsWith('http://') && !url.startsWith('https://')) {\n return { matches: false };\n }\n\n // Must be huggingface.co\n try {\n const parsed = new URL(url);\n if (parsed.hostname !== this.HOST) {\n return { matches: false };\n }\n } catch {\n return { matches: false };\n }\n\n // Must end with SKILL.md (case insensitive)\n if (!url.toLowerCase().endsWith('/skill.md')) {\n return { matches: false };\n }\n\n // Must be a spaces URL\n if (!url.includes('/spaces/')) {\n return { matches: false };\n }\n\n return { matches: true };\n }\n\n async fetchSkill(url: string): Promise<RemoteSkill | null> {\n try {\n // Convert to raw URL\n const rawUrl = this.toRawUrl(url);\n\n const response = await fetch(rawUrl, { signal: AbortSignal.timeout(30000) });\n\n if (!response.ok) {\n return null;\n }\n\n const content = await response.text();\n const { data } = matter(content);\n\n // Must have name and description\n if (!data.name || !data.description) {\n return null;\n }\n\n // Extract owner/repo from URL for install name\n const parsed = this.parseUrl(url);\n if (!parsed) {\n return null;\n }\n\n // Use metadata.install-name if provided, otherwise use repo name\n const installName = data.metadata?.['install-name'] || parsed.repo;\n\n return {\n name: data.name,\n description: data.description,\n content,\n installName,\n sourceUrl: url,\n metadata: data.metadata,\n };\n } catch {\n return null;\n }\n }\n\n toRawUrl(url: string): string {\n // Convert blob URL to raw URL\n // https://huggingface.co/spaces/owner/repo/blob/main/SKILL.md\n // -> https://huggingface.co/spaces/owner/repo/raw/main/SKILL.md\n return url.replace('/blob/', '/raw/');\n }\n\n getSourceIdentifier(url: string): string {\n const parsed = this.parseUrl(url);\n if (!parsed) {\n return 'huggingface/unknown';\n }\n return `huggingface/${parsed.owner}/${parsed.repo}`;\n }\n\n /**\n * Parse a HuggingFace Spaces URL to extract owner and repo.\n */\n private parseUrl(url: string): { owner: string; repo: string } | null {\n // Match: /spaces/{owner}/{repo}/\n const match = url.match(/\\/spaces\\/([^/]+)\\/([^/]+)/);\n if (!match || !match[1] || !match[2]) {\n return null;\n }\n return {\n owner: match[1],\n repo: match[2],\n };\n }\n}\n\nexport const huggingFaceProvider = new HuggingFaceProvider();\n","import matter from 'gray-matter';\nimport type { HostProvider, ProviderMatch, RemoteSkill } from './types.ts';\n\n/**\n * Represents the index.json structure for well-known skills.\n */\nexport interface WellKnownIndex {\n skills: WellKnownSkillEntry[];\n}\n\n/**\n * Represents a skill entry in the index.json.\n */\nexport interface WellKnownSkillEntry {\n /** Skill identifier. Must match the directory name. */\n name: string;\n /** Brief description of what the skill does. */\n description: string;\n /** Array of all files in the skill directory. */\n files: string[];\n}\n\n/**\n * Represents a skill with all its files fetched from a well-known endpoint.\n */\nexport interface WellKnownSkill extends RemoteSkill {\n /** All files in the skill, keyed by relative path */\n files: Map<string, string>;\n /** The entry from the index.json */\n indexEntry: WellKnownSkillEntry;\n}\n\n/**\n * Well-known skills provider using RFC 8615 well-known URIs.\n *\n * Organizations can publish skills at:\n * https://example.com/.well-known/skills/\n *\n * URL formats supported:\n * - https://example.com (discovers all skills from root)\n * - https://example.com/docs (discovers from /docs/.well-known/skills/)\n * - https://example.com/.well-known/skills (discovers all skills)\n * - https://example.com/.well-known/skills/skill-name (specific skill)\n *\n * The source identifier is \"wellknown/{hostname}\" or \"wellknown/{hostname}/path\".\n */\nexport class WellKnownProvider implements HostProvider {\n readonly id = 'well-known';\n readonly displayName = 'Well-Known Skills';\n\n private readonly WELL_KNOWN_PATH = '.well-known/skills';\n private readonly INDEX_FILE = 'index.json';\n\n /**\n * Check if a URL could be a well-known skills endpoint.\n * This is a fallback provider - it matches any HTTP(S) URL that is not\n * a recognized pattern (GitHub, GitLab, owner/repo shorthand, etc.)\n */\n match(url: string): ProviderMatch {\n // Must be a valid HTTP(S) URL\n if (!url.startsWith('http://') && !url.startsWith('https://')) {\n return { matches: false };\n }\n\n // Parse URL to extract hostname\n try {\n const parsed = new URL(url);\n\n // Exclude known git hosts that have their own handling\n const excludedHosts = ['github.com', 'gitlab.com', 'huggingface.co'];\n if (excludedHosts.includes(parsed.hostname)) {\n return { matches: false };\n }\n\n return {\n matches: true,\n sourceIdentifier: `wellknown/${parsed.hostname}`,\n };\n } catch {\n return { matches: false };\n }\n }\n\n /**\n * Fetch the skills index from a well-known endpoint.\n * Tries both the path-relative .well-known and the root .well-known.\n */\n async fetchIndex(\n baseUrl: string\n ): Promise<{ index: WellKnownIndex; resolvedBaseUrl: string } | null> {\n try {\n const parsed = new URL(baseUrl);\n const basePath = parsed.pathname.replace(/\\/$/, ''); // Remove trailing slash\n\n // Try path-relative .well-known first (e.g., /docs/.well-known/skills/)\n // then fall back to root .well-known\n const urlsToTry = [\n // Path-relative: https://example.com/docs/.well-known/skills/index.json\n {\n indexUrl: `${parsed.protocol}//${parsed.host}${basePath}/${this.WELL_KNOWN_PATH}/${this.INDEX_FILE}`,\n baseUrl: `${parsed.protocol}//${parsed.host}${basePath}`,\n },\n ];\n\n // Also try root if we have a path\n if (basePath && basePath !== '') {\n urlsToTry.push({\n indexUrl: `${parsed.protocol}//${parsed.host}/${this.WELL_KNOWN_PATH}/${this.INDEX_FILE}`,\n baseUrl: `${parsed.protocol}//${parsed.host}`,\n });\n }\n\n for (const { indexUrl, baseUrl: resolvedBase } of urlsToTry) {\n try {\n const response = await fetch(indexUrl);\n\n if (!response.ok) {\n continue;\n }\n\n const index = (await response.json()) as WellKnownIndex;\n\n // Validate index structure\n if (!index.skills || !Array.isArray(index.skills)) {\n continue;\n }\n\n // Validate each skill entry\n let allValid = true;\n for (const entry of index.skills) {\n if (!this.isValidSkillEntry(entry)) {\n allValid = false;\n break;\n }\n }\n\n if (allValid) {\n return { index, resolvedBaseUrl: resolvedBase };\n }\n } catch {\n // Try next URL\n continue;\n }\n }\n\n return null;\n } catch {\n return null;\n }\n }\n\n /**\n * Validate a skill entry from the index.\n */\n private isValidSkillEntry(entry: unknown): entry is WellKnownSkillEntry {\n if (!entry || typeof entry !== 'object') return false;\n\n const e = entry as Record<string, unknown>;\n\n // Required fields\n if (typeof e.name !== 'string' || !e.name) return false;\n if (typeof e.description !== 'string' || !e.description) return false;\n if (!Array.isArray(e.files) || e.files.length === 0) return false;\n\n // Validate name format (per spec: 1-64 chars, lowercase alphanumeric and hyphens)\n const nameRegex = /^[a-z0-9]([a-z0-9-]{0,62}[a-z0-9])?$/;\n if (!nameRegex.test(e.name) && e.name.length > 1) {\n // Allow single char names like \"a\"\n if (e.name.length === 1 && !/^[a-z0-9]$/.test(e.name)) {\n return false;\n }\n }\n\n // Validate files array\n for (const file of e.files) {\n if (typeof file !== 'string') return false;\n // Files must not start with / or \\ or contain .. (path traversal prevention)\n if (file.startsWith('/') || file.startsWith('\\\\') || file.includes('..')) return false;\n }\n\n // Must include SKILL.md\n const hasSkillMd = e.files.some((f) => typeof f === 'string' && f.toLowerCase() === 'skill.md');\n if (!hasSkillMd) return false;\n\n return true;\n }\n\n /**\n * Fetch a single skill and all its files from a well-known endpoint.\n */\n async fetchSkill(url: string): Promise<RemoteSkill | null> {\n try {\n const parsed = new URL(url);\n\n // First, fetch the index to get skill metadata\n const result = await this.fetchIndex(url);\n if (!result) {\n return null;\n }\n\n const { index, resolvedBaseUrl } = result;\n\n // Determine which skill to fetch\n let skillName: string | null = null;\n\n // Check if URL specifies a specific skill\n const pathMatch = parsed.pathname.match(/\\/.well-known\\/skills\\/([^/]+)\\/?$/);\n if (pathMatch && pathMatch[1] && pathMatch[1] !== 'index.json') {\n skillName = pathMatch[1];\n } else if (index.skills.length === 1) {\n // If only one skill in index, use that\n skillName = index.skills[0]!.name;\n }\n\n if (!skillName) {\n // Multiple skills available, return null - caller should use fetchAllSkills\n return null;\n }\n\n // Find the skill in the index\n const skillEntry = index.skills.find((s: WellKnownSkillEntry) => s.name === skillName);\n if (!skillEntry) {\n return null;\n }\n\n return this.fetchSkillByEntry(resolvedBaseUrl, skillEntry);\n } catch {\n return null;\n }\n }\n\n /**\n * Fetch a skill by its index entry.\n * @param baseUrl - The base URL (e.g., https://example.com or https://example.com/docs)\n * @param entry - The skill entry from index.json\n */\n async fetchSkillByEntry(\n baseUrl: string,\n entry: WellKnownSkillEntry\n ): Promise<WellKnownSkill | null> {\n try {\n // Build the skill base URL: {baseUrl}/.well-known/skills/{skill-name}\n const skillBaseUrl = `${baseUrl.replace(/\\/$/, '')}/${this.WELL_KNOWN_PATH}/${entry.name}`;\n\n // Fetch SKILL.md first (required)\n const skillMdUrl = `${skillBaseUrl}/SKILL.md`;\n const response = await fetch(skillMdUrl);\n\n if (!response.ok) {\n return null;\n }\n\n const content = await response.text();\n const { data } = matter(content);\n\n // Validate frontmatter has name and description\n if (!data.name || !data.description) {\n return null;\n }\n\n // Fetch all other files\n const files = new Map<string, string>();\n files.set('SKILL.md', content);\n\n // Fetch remaining files in parallel\n const otherFiles = entry.files.filter((f) => f.toLowerCase() !== 'skill.md');\n const filePromises = otherFiles.map(async (filePath) => {\n try {\n const fileUrl = `${skillBaseUrl}/${filePath}`;\n const fileResponse = await fetch(fileUrl);\n if (fileResponse.ok) {\n const fileContent = await fileResponse.text();\n return { path: filePath, content: fileContent };\n }\n } catch {\n // Ignore individual file fetch errors\n }\n return null;\n });\n\n const fileResults = await Promise.all(filePromises);\n for (const result of fileResults) {\n if (result) {\n files.set(result.path, result.content);\n }\n }\n\n return {\n name: data.name,\n description: data.description,\n content,\n installName: entry.name,\n sourceUrl: skillMdUrl,\n metadata: data.metadata,\n files,\n indexEntry: entry,\n };\n } catch {\n return null;\n }\n }\n\n /**\n * Fetch all skills from a well-known endpoint.\n */\n async fetchAllSkills(url: string): Promise<WellKnownSkill[]> {\n try {\n const result = await this.fetchIndex(url);\n if (!result) {\n return [];\n }\n\n const { index, resolvedBaseUrl } = result;\n\n // Fetch all skills in parallel\n const skillPromises = index.skills.map((entry: WellKnownSkillEntry) =>\n this.fetchSkillByEntry(resolvedBaseUrl, entry)\n );\n const results = await Promise.all(skillPromises);\n\n return results.filter((s: WellKnownSkill | null): s is WellKnownSkill => s !== null);\n } catch {\n return [];\n }\n }\n\n /**\n * Convert a user-facing URL to a skill URL.\n * For well-known, this extracts the base domain and constructs the proper path.\n */\n toRawUrl(url: string): string {\n try {\n const parsed = new URL(url);\n // If already pointing to a SKILL.md, return as-is\n if (url.toLowerCase().endsWith('/skill.md')) {\n return url;\n }\n\n // Check if URL specifies a skill path\n const pathMatch = parsed.pathname.match(/\\/.well-known\\/skills\\/([^/]+)\\/?$/);\n if (pathMatch && pathMatch[1]) {\n const basePath = parsed.pathname.replace(/\\/.well-known\\/skills\\/.*$/, '');\n return `${parsed.protocol}//${parsed.host}${basePath}/${this.WELL_KNOWN_PATH}/${pathMatch[1]}/SKILL.md`;\n }\n\n // Otherwise, return the index URL\n const basePath = parsed.pathname.replace(/\\/$/, '');\n return `${parsed.protocol}//${parsed.host}${basePath}/${this.WELL_KNOWN_PATH}/${this.INDEX_FILE}`;\n } catch {\n return url;\n }\n }\n\n /**\n * Get the source identifier for telemetry/storage.\n * Returns the domain in owner/repo format: second-level-domain/top-level-domain.\n * e.g., \"mintlify.com\" → \"mintlify/com\", \"lovable.dev\" → \"lovable/dev\"\n * This matches the owner/repo pattern used by GitHub sources for consistency in the leaderboard.\n */\n getSourceIdentifier(url: string): string {\n try {\n const parsed = new URL(url);\n // Extract the main domain (ignore subdomains like \"docs.\" or \"api.\")\n const hostParts = parsed.hostname.split('.');\n\n // Handle common cases:\n // - example.com → example/com\n // - docs.example.com → example/com (strip subdomain)\n // - example.co.uk → example/co.uk (keep compound TLD)\n\n if (hostParts.length >= 2) {\n // Get the last two parts as the main domain\n const tld = hostParts[hostParts.length - 1]; // com, dev, io, etc.\n const sld = hostParts[hostParts.length - 2]; // mintlify, lovable, etc.\n return `${sld}/${tld}`;\n }\n\n // Fallback for unusual hostnames\n return parsed.hostname.replace('.', '/');\n } catch {\n return 'unknown/unknown';\n }\n }\n\n /**\n * Check if a URL has a well-known skills index.\n */\n async hasSkillsIndex(url: string): Promise<boolean> {\n const result = await this.fetchIndex(url);\n return result !== null;\n }\n}\n\nexport const wellKnownProvider = new WellKnownProvider();\n","// Export types\nexport type { HostProvider, ProviderMatch, ProviderRegistry, RemoteSkill } from './types.ts';\n\n// Export registry functions\nexport { registry, registerProvider, findProvider, getProviders } from './registry.ts';\n\n// Export individual providers\nexport { MintlifyProvider, mintlifyProvider } from './mintlify.ts';\nexport { HuggingFaceProvider, huggingFaceProvider } from './huggingface.ts';\nexport {\n WellKnownProvider,\n wellKnownProvider,\n type WellKnownIndex,\n type WellKnownSkillEntry,\n type WellKnownSkill,\n} from './wellknown.ts';\n\n// Register all built-in providers\nimport { registerProvider } from './registry.ts';\nimport { mintlifyProvider } from './mintlify.ts';\nimport { huggingFaceProvider } from './huggingface.ts';\nimport { wellKnownProvider } from './wellknown.ts';\n\nregisterProvider(mintlifyProvider);\nregisterProvider(huggingFaceProvider);\n// Note: wellKnownProvider is NOT registered here - it's a fallback provider\n// that should only be used explicitly when parsing detects a well-known URL\n","import matter from 'gray-matter';\nimport type { MintlifySkill } from './types.ts';\n\n/**\n * Fetch a skill.md file from a direct URL and parse its contents\n * Looks for `mintlify-proj` in metadata.mintlify-proj to identify Mintlify-hosted skills\n *\n * Expected frontmatter format:\n * ---\n * name: Bun Development\n * description: Build applications with Bun runtime\n * metadata:\n * mintlify-proj: bun.com\n * ---\n */\nexport async function fetchMintlifySkill(url: string): Promise<MintlifySkill | null> {\n try {\n const response = await fetch(url, { signal: AbortSignal.timeout(30000) });\n\n if (!response.ok) {\n return null;\n }\n\n const content = await response.text();\n const { data } = matter(content);\n\n // Must have mintlify-proj in metadata\n const mintlifySite = data.metadata?.['mintlify-proj'];\n if (!mintlifySite) {\n return null;\n }\n\n // Must have name and description\n if (!data.name || !data.description) {\n return null;\n }\n\n return {\n name: data.name,\n description: data.description,\n content: content, // Full content including frontmatter\n mintlifySite: mintlifySite,\n sourceUrl: url,\n };\n } catch {\n return null;\n }\n}\n\n/**\n * Check if a direct URL skill.md is a Mintlify-hosted skill\n * by fetching and checking for mintlify-proj frontmatter\n */\nexport async function isMintlifySkill(url: string): Promise<boolean> {\n const skill = await fetchMintlifySkill(url);\n return skill !== null;\n}\n","import { readFile, writeFile, mkdir } from 'fs/promises';\nimport { join, dirname } from 'path';\nimport { homedir } from 'os';\nimport { createHash } from 'crypto';\nimport { execSync } from 'child_process';\n\nconst AGENTS_DIR = '.agents';\nconst LOCK_FILE = '.skill-lock.json';\nconst CURRENT_VERSION = 3; // Bumped from 2 to 3 for folder hash support (GitHub tree SHA)\n\n/**\n * Represents a single installed skill entry in the lock file.\n */\nexport interface SkillLockEntry {\n /** Normalized source identifier (e.g., \"owner/repo\", \"mintlify/bun.com\") */\n source: string;\n /** The provider/source type (e.g., \"github\", \"mintlify\", \"huggingface\", \"local\") */\n sourceType: string;\n /** The original URL used to install the skill (for re-fetching updates) */\n sourceUrl: string;\n /** Subpath within the source repo, if applicable */\n skillPath?: string;\n /**\n * GitHub tree SHA for the entire skill folder.\n * This hash changes when ANY file in the skill folder changes.\n * Fetched via GitHub Trees API by the telemetry server.\n */\n skillFolderHash: string;\n /** ISO timestamp when the skill was first installed */\n installedAt: string;\n /** ISO timestamp when the skill was last updated */\n updatedAt: string;\n /** Name of the plugin this skill belongs to (if any) */\n pluginName?: string;\n}\n\n/**\n * Tracks dismissed prompts so they're not shown again.\n */\nexport interface DismissedPrompts {\n /** Dismissed the find-skills skill installation prompt */\n findSkillsPrompt?: boolean;\n}\n\n/**\n * The structure of the skill lock file.\n */\nexport interface SkillLockFile {\n /** Schema version for future migrations */\n version: number;\n /** Map of skill name to its lock entry */\n skills: Record<string, SkillLockEntry>;\n /** Tracks dismissed prompts */\n dismissed?: DismissedPrompts;\n /** Last selected agents for installation */\n lastSelectedAgents?: string[];\n}\n\n/**\n * Get the path to the global skill lock file.\n * Located at ~/.agents/.skill-lock.json\n */\nexport function getSkillLockPath(): string {\n return join(homedir(), AGENTS_DIR, LOCK_FILE);\n}\n\n/**\n * Read the skill lock file.\n * Returns an empty lock file structure if the file doesn't exist.\n * Wipes the lock file if it's an old format (version < CURRENT_VERSION).\n */\nexport async function readSkillLock(): Promise<SkillLockFile> {\n const lockPath = getSkillLockPath();\n\n try {\n const content = await readFile(lockPath, 'utf-8');\n const parsed = JSON.parse(content) as SkillLockFile;\n\n // Validate version - wipe if old format\n if (typeof parsed.version !== 'number' || !parsed.skills) {\n return createEmptyLockFile();\n }\n\n // If old version, wipe and start fresh (backwards incompatible change)\n // v3 adds skillFolderHash - we want fresh installs to populate it\n if (parsed.version < CURRENT_VERSION) {\n return createEmptyLockFile();\n }\n\n return parsed;\n } catch (error) {\n // File doesn't exist or is invalid - return empty\n return createEmptyLockFile();\n }\n}\n\n/**\n * Write the skill lock file.\n * Creates the directory if it doesn't exist.\n */\nexport async function writeSkillLock(lock: SkillLockFile): Promise<void> {\n const lockPath = getSkillLockPath();\n\n // Ensure directory exists\n await mkdir(dirname(lockPath), { recursive: true });\n\n // Write with pretty formatting for human readability\n const content = JSON.stringify(lock, null, 2);\n await writeFile(lockPath, content, 'utf-8');\n}\n\n/**\n * Compute SHA-256 hash of content.\n */\nexport function computeContentHash(content: string): string {\n return createHash('sha256').update(content, 'utf-8').digest('hex');\n}\n\n/**\n * Get GitHub token from user's environment.\n * Tries in order:\n * 1. GITHUB_TOKEN environment variable\n * 2. GH_TOKEN environment variable\n * 3. gh CLI auth token (if gh is installed)\n *\n * @returns The token string or null if not available\n */\nexport function getGitHubToken(): string | null {\n // Check environment variables first\n if (process.env.GITHUB_TOKEN) {\n return process.env.GITHUB_TOKEN;\n }\n if (process.env.GH_TOKEN) {\n return process.env.GH_TOKEN;\n }\n\n // Try gh CLI\n try {\n const token = execSync('gh auth token', {\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n }).trim();\n if (token) {\n return token;\n }\n } catch {\n // gh not installed or not authenticated\n }\n\n return null;\n}\n\n/**\n * Fetch the tree SHA (folder hash) for a skill folder using GitHub's Trees API.\n * This makes ONE API call to get the entire repo tree, then extracts the SHA\n * for the specific skill folder.\n *\n * @param ownerRepo - GitHub owner/repo (e.g., \"vercel-labs/agent-skills\")\n * @param skillPath - Path to skill folder or SKILL.md (e.g., \"skills/react-best-practices/SKILL.md\")\n * @param token - Optional GitHub token for authenticated requests (higher rate limits)\n * @returns The tree SHA for the skill folder, or null if not found\n */\nexport async function fetchSkillFolderHash(\n ownerRepo: string,\n skillPath: string,\n token?: string | null\n): Promise<string | null> {\n // Normalize to forward slashes first (for GitHub API compatibility)\n let folderPath = skillPath.replace(/\\\\/g, '/');\n\n // Remove SKILL.md suffix to get folder path\n if (folderPath.endsWith('/SKILL.md')) {\n folderPath = folderPath.slice(0, -9);\n } else if (folderPath.endsWith('SKILL.md')) {\n folderPath = folderPath.slice(0, -8);\n }\n\n // Remove trailing slash\n if (folderPath.endsWith('/')) {\n folderPath = folderPath.slice(0, -1);\n }\n\n const branches = ['main', 'master'];\n\n for (const branch of branches) {\n try {\n const url = `https://api.github.com/repos/${ownerRepo}/git/trees/${branch}?recursive=1`;\n const headers: Record<string, string> = {\n Accept: 'application/vnd.github.v3+json',\n 'User-Agent': 'skills-cli',\n };\n if (token) {\n headers['Authorization'] = `Bearer ${token}`;\n }\n\n const response = await fetch(url, { headers });\n\n if (!response.ok) continue;\n\n const data = (await response.json()) as {\n sha: string;\n tree: Array<{ path: string; type: string; sha: string }>;\n };\n\n // If folderPath is empty, this is a root-level skill - use the root tree SHA\n if (!folderPath) {\n return data.sha;\n }\n\n // Find the tree entry for the skill folder\n const folderEntry = data.tree.find(\n (entry) => entry.type === 'tree' && entry.path === folderPath\n );\n\n if (folderEntry) {\n return folderEntry.sha;\n }\n } catch {\n continue;\n }\n }\n\n return null;\n}\n\n/**\n * Add or update a skill entry in the lock file.\n */\nexport async function addSkillToLock(\n skillName: string,\n entry: Omit<SkillLockEntry, 'installedAt' | 'updatedAt'>\n): Promise<void> {\n const lock = await readSkillLock();\n const now = new Date().toISOString();\n\n const existingEntry = lock.skills[skillName];\n\n lock.skills[skillName] = {\n ...entry,\n installedAt: existingEntry?.installedAt ?? now,\n updatedAt: now,\n };\n\n await writeSkillLock(lock);\n}\n\n/**\n * Remove a skill from the lock file.\n */\nexport async function removeSkillFromLock(skillName: string): Promise<boolean> {\n const lock = await readSkillLock();\n\n if (!(skillName in lock.skills)) {\n return false;\n }\n\n delete lock.skills[skillName];\n await writeSkillLock(lock);\n return true;\n}\n\n/**\n * Get a skill entry from the lock file.\n */\nexport async function getSkillFromLock(skillName: string): Promise<SkillLockEntry | null> {\n const lock = await readSkillLock();\n return lock.skills[skillName] ?? null;\n}\n\n/**\n * Get all skills from the lock file.\n */\nexport async function getAllLockedSkills(): Promise<Record<string, SkillLockEntry>> {\n const lock = await readSkillLock();\n return lock.skills;\n}\n\n/**\n * Get skills grouped by source for batch update operations.\n */\nexport async function getSkillsBySource(): Promise<\n Map<string, { skills: string[]; entry: SkillLockEntry }>\n> {\n const lock = await readSkillLock();\n const bySource = new Map<string, { skills: string[]; entry: SkillLockEntry }>();\n\n for (const [skillName, entry] of Object.entries(lock.skills)) {\n const existing = bySource.get(entry.source);\n if (existing) {\n existing.skills.push(skillName);\n } else {\n bySource.set(entry.source, { skills: [skillName], entry });\n }\n }\n\n return bySource;\n}\n\n/**\n * Create an empty lock file structure.\n */\nfunction createEmptyLockFile(): SkillLockFile {\n return {\n version: CURRENT_VERSION,\n skills: {},\n dismissed: {},\n };\n}\n\n/**\n * Check if a prompt has been dismissed.\n */\nexport async function isPromptDismissed(promptKey: keyof DismissedPrompts): Promise<boolean> {\n const lock = await readSkillLock();\n return lock.dismissed?.[promptKey] === true;\n}\n\n/**\n * Mark a prompt as dismissed.\n */\nexport async function dismissPrompt(promptKey: keyof DismissedPrompts): Promise<void> {\n const lock = await readSkillLock();\n if (!lock.dismissed) {\n lock.dismissed = {};\n }\n lock.dismissed[promptKey] = true;\n await writeSkillLock(lock);\n}\n\n/**\n * Get the last selected agents.\n */\nexport async function getLastSelectedAgents(): Promise<string[] | undefined> {\n const lock = await readSkillLock();\n return lock.lastSelectedAgents;\n}\n\n/**\n * Save the selected agents to the lock file.\n */\nexport async function saveSelectedAgents(agents: string[]): Promise<void> {\n const lock = await readSkillLock();\n lock.lastSelectedAgents = agents;\n await writeSkillLock(lock);\n}\n","import { readFile, writeFile, readdir, stat } from 'fs/promises';\nimport { join, relative } from 'path';\nimport { createHash } from 'crypto';\n\nconst LOCAL_LOCK_FILE = 'skills-lock.json';\nconst CURRENT_VERSION = 1;\n\n/**\n * Represents a single skill entry in the local (project) lock file.\n *\n * Intentionally minimal and timestamp-free to minimize merge conflicts.\n * Two branches adding different skills produce non-overlapping JSON keys\n * that git can auto-merge cleanly.\n */\nexport interface LocalSkillLockEntry {\n /** Where the skill came from: npm package name, owner/repo, local path, etc. */\n source: string;\n /** The provider/source type (e.g., \"github\", \"node_modules\", \"local\") */\n sourceType: string;\n /**\n * SHA-256 hash computed from all files in the skill folder.\n * Unlike the global lock which uses GitHub tree SHA, the local lock\n * computes the hash from actual file contents on disk.\n */\n computedHash: string;\n}\n\n/**\n * The structure of the local (project-scoped) skill lock file.\n * This file is meant to be checked into version control.\n *\n * Skills are sorted alphabetically by name when written to produce\n * deterministic output and minimize merge conflicts.\n */\nexport interface LocalSkillLockFile {\n /** Schema version for future migrations */\n version: number;\n /** Map of skill name to its lock entry (sorted alphabetically) */\n skills: Record<string, LocalSkillLockEntry>;\n}\n\n/**\n * Get the path to the local skill lock file for a project.\n */\nexport function getLocalLockPath(cwd?: string): string {\n return join(cwd || process.cwd(), LOCAL_LOCK_FILE);\n}\n\n/**\n * Read the local skill lock file.\n * Returns an empty lock file structure if the file doesn't exist\n * or is corrupted (e.g., merge conflict markers).\n */\nexport async function readLocalLock(cwd?: string): Promise<LocalSkillLockFile> {\n const lockPath = getLocalLockPath(cwd);\n\n try {\n const content = await readFile(lockPath, 'utf-8');\n const parsed = JSON.parse(content) as LocalSkillLockFile;\n\n if (typeof parsed.version !== 'number' || !parsed.skills) {\n return createEmptyLocalLock();\n }\n\n if (parsed.version < CURRENT_VERSION) {\n return createEmptyLocalLock();\n }\n\n return parsed;\n } catch {\n return createEmptyLocalLock();\n }\n}\n\n/**\n * Write the local skill lock file.\n * Skills are sorted alphabetically by name for deterministic output.\n */\nexport async function writeLocalLock(lock: LocalSkillLockFile, cwd?: string): Promise<void> {\n const lockPath = getLocalLockPath(cwd);\n\n // Sort skills alphabetically for deterministic output / clean diffs\n const sortedSkills: Record<string, LocalSkillLockEntry> = {};\n for (const key of Object.keys(lock.skills).sort()) {\n sortedSkills[key] = lock.skills[key]!;\n }\n\n const sorted: LocalSkillLockFile = { version: lock.version, skills: sortedSkills };\n const content = JSON.stringify(sorted, null, 2) + '\\n';\n await writeFile(lockPath, content, 'utf-8');\n}\n\n/**\n * Compute a SHA-256 hash from all files in a skill directory.\n * Reads all files recursively, sorts them by relative path for determinism,\n * and produces a single hash from their concatenated contents.\n */\nexport async function computeSkillFolderHash(skillDir: string): Promise<string> {\n const files: Array<{ relativePath: string; content: Buffer }> = [];\n await collectFiles(skillDir, skillDir, files);\n\n // Sort by relative path for deterministic hashing\n files.sort((a, b) => a.relativePath.localeCompare(b.relativePath));\n\n const hash = createHash('sha256');\n for (const file of files) {\n // Include the path in the hash so renames are detected\n hash.update(file.relativePath);\n hash.update(file.content);\n }\n\n return hash.digest('hex');\n}\n\nasync function collectFiles(\n baseDir: string,\n currentDir: string,\n results: Array<{ relativePath: string; content: Buffer }>\n): Promise<void> {\n const entries = await readdir(currentDir, { withFileTypes: true });\n\n await Promise.all(\n entries.map(async (entry) => {\n const fullPath = join(currentDir, entry.name);\n\n if (entry.isDirectory()) {\n // Skip .git and node_modules within skill dirs\n if (entry.name === '.git' || entry.name === 'node_modules') return;\n await collectFiles(baseDir, fullPath, results);\n } else if (entry.isFile()) {\n const content = await readFile(fullPath);\n const relativePath = relative(baseDir, fullPath).split('\\\\').join('/');\n results.push({ relativePath, content });\n }\n })\n );\n}\n\n/**\n * Add or update a skill entry in the local lock file.\n */\nexport async function addSkillToLocalLock(\n skillName: string,\n entry: LocalSkillLockEntry,\n cwd?: string\n): Promise<void> {\n const lock = await readLocalLock(cwd);\n lock.skills[skillName] = entry;\n await writeLocalLock(lock, cwd);\n}\n\n/**\n * Remove a skill from the local lock file.\n */\nexport async function removeSkillFromLocalLock(skillName: string, cwd?: string): Promise<boolean> {\n const lock = await readLocalLock(cwd);\n\n if (!(skillName in lock.skills)) {\n return false;\n }\n\n delete lock.skills[skillName];\n await writeLocalLock(lock, cwd);\n return true;\n}\n\nfunction createEmptyLocalLock(): LocalSkillLockFile {\n return {\n version: CURRENT_VERSION,\n skills: {},\n };\n}\n","","import * as p from '@clack/prompts';\nimport pc from 'picocolors';\nimport { existsSync } from 'fs';\nimport { homedir } from 'os';\nimport { sep } from 'path';\nimport { parseSource, getOwnerRepo, parseOwnerRepo, isRepoPrivate } from './source-parser.ts';\nimport { searchMultiselect, cancelSymbol } from './prompts/search-multiselect.ts';\n\n// Helper to check if a value is a cancel symbol (works with both clack and our custom prompts)\nconst isCancelled = (value: unknown): value is symbol => typeof value === 'symbol';\n\n/**\n * Check if a source identifier (owner/repo format) represents a private GitHub repo.\n * Returns true if private, false if public, null if unable to determine or not a GitHub repo.\n */\nasync function isSourcePrivate(source: string): Promise<boolean | null> {\n const ownerRepo = parseOwnerRepo(source);\n if (!ownerRepo) {\n // Not in owner/repo format, assume not private (could be other providers)\n return false;\n }\n return isRepoPrivate(ownerRepo.owner, ownerRepo.repo);\n}\nimport { cloneRepo, cleanupTempDir, GitCloneError } from './git.ts';\nimport { discoverSkills, getSkillDisplayName, filterSkills } from './skills.ts';\nimport {\n installSkillForAgent,\n isSkillInstalled,\n getInstallPath,\n getCanonicalPath,\n installRemoteSkillForAgent,\n installWellKnownSkillForAgent,\n type InstallMode,\n} from './installer.ts';\nimport {\n detectInstalledAgents,\n agents,\n getUniversalAgents,\n getNonUniversalAgents,\n isUniversalAgent,\n} from './agents.ts';\nimport {\n track,\n setVersion,\n fetchAuditData,\n type AuditResponse,\n type SkillAuditData,\n type PartnerAudit,\n} from './telemetry.ts';\nimport { findProvider, wellKnownProvider, type WellKnownSkill } from './providers/index.ts';\nimport { fetchMintlifySkill } from './mintlify.ts';\nimport {\n addSkillToLock,\n fetchSkillFolderHash,\n isPromptDismissed,\n dismissPrompt,\n getLastSelectedAgents,\n saveSelectedAgents,\n} from './skill-lock.ts';\nimport { addSkillToLocalLock, computeSkillFolderHash } from './local-lock.ts';\nimport type { Skill, AgentType, RemoteSkill } from './types.ts';\nimport packageJson from '../package.json' with { type: 'json' };\nexport function initTelemetry(version: string): void {\n setVersion(version);\n}\n\n// ─── Security Advisory ───\n\nfunction riskLabel(risk: string): string {\n switch (risk) {\n case 'critical':\n return pc.red(pc.bold('Critical Risk'));\n case 'high':\n return pc.red('High Risk');\n case 'medium':\n return pc.yellow('Med Risk');\n case 'low':\n return pc.green('Low Risk');\n case 'safe':\n return pc.green('Safe');\n default:\n return pc.dim('--');\n }\n}\n\nfunction socketLabel(audit: PartnerAudit | undefined): string {\n if (!audit) return pc.dim('--');\n const count = audit.alerts ?? 0;\n return count > 0 ? pc.red(`${count} alert${count !== 1 ? 's' : ''}`) : pc.green('0 alerts');\n}\n\n/** Pad a string to a given visible width (ignoring ANSI escape codes). */\nfunction padEnd(str: string, width: number): string {\n // Strip ANSI codes to measure visible length\n const visible = str.replace(/\\x1b\\[[0-9;]*m/g, '');\n const pad = Math.max(0, width - visible.length);\n return str + ' '.repeat(pad);\n}\n\n/**\n * Render a compact security table showing partner audit results.\n * Returns the lines to display, or empty array if no data.\n */\nfunction buildSecurityLines(\n auditData: AuditResponse | null,\n skills: Array<{ slug: string; displayName: string }>,\n source: string\n): string[] {\n if (!auditData) return [];\n\n // Check if we have any audit data at all\n const hasAny = skills.some((s) => {\n const data = auditData[s.slug];\n return data && Object.keys(data).length > 0;\n });\n if (!hasAny) return [];\n\n // Compute column width for skill names\n const nameWidth = Math.min(Math.max(...skills.map((s) => s.displayName.length)), 36);\n\n // Header\n const lines: string[] = [];\n const header =\n padEnd('', nameWidth + 2) +\n padEnd(pc.dim('Gen'), 18) +\n padEnd(pc.dim('Socket'), 18) +\n pc.dim('Snyk');\n lines.push(header);\n\n // Rows\n for (const skill of skills) {\n const data = auditData[skill.slug];\n const name =\n skill.displayName.length > nameWidth\n ? skill.displayName.slice(0, nameWidth - 1) + '\\u2026'\n : skill.displayName;\n\n const ath = data?.ath ? riskLabel(data.ath.risk) : pc.dim('--');\n const socket = data?.socket ? socketLabel(data.socket) : pc.dim('--');\n const snyk = data?.snyk ? riskLabel(data.snyk.risk) : pc.dim('--');\n\n lines.push(padEnd(pc.cyan(name), nameWidth + 2) + padEnd(ath, 18) + padEnd(socket, 18) + snyk);\n }\n\n // Footer link\n lines.push('');\n lines.push(`${pc.dim('Details:')} ${pc.dim(`https://skills.sh/${source}`)}`);\n\n return lines;\n}\n\n/**\n * Shortens a path for display: replaces homedir with ~ and cwd with .\n * Handles both Unix and Windows path separators.\n */\nfunction shortenPath(fullPath: string, cwd: string): string {\n const home = homedir();\n // Ensure we match complete path segments by checking for separator after the prefix\n if (fullPath === home || fullPath.startsWith(home + sep)) {\n return '~' + fullPath.slice(home.length);\n }\n if (fullPath === cwd || fullPath.startsWith(cwd + sep)) {\n return '.' + fullPath.slice(cwd.length);\n }\n return fullPath;\n}\n\n/**\n * Formats a list of items, truncating if too many\n */\nfunction formatList(items: string[], maxShow: number = 5): string {\n if (items.length <= maxShow) {\n return items.join(', ');\n }\n const shown = items.slice(0, maxShow);\n const remaining = items.length - maxShow;\n return `${shown.join(', ')} +${remaining} more`;\n}\n\n/**\n * Splits agents into universal and non-universal (symlinked) groups.\n * Returns display names for each group.\n */\nfunction splitAgentsByType(agentTypes: AgentType[]): {\n universal: string[];\n symlinked: string[];\n} {\n const universal: string[] = [];\n const symlinked: string[] = [];\n\n for (const a of agentTypes) {\n if (isUniversalAgent(a)) {\n universal.push(agents[a].displayName);\n } else {\n symlinked.push(agents[a].displayName);\n }\n }\n\n return { universal, symlinked };\n}\n\n/**\n * Builds summary lines showing universal vs symlinked agents\n */\nfunction buildAgentSummaryLines(targetAgents: AgentType[], installMode: InstallMode): string[] {\n const lines: string[] = [];\n const { universal, symlinked } = splitAgentsByType(targetAgents);\n\n if (installMode === 'mcp-server') {\n lines.push(` ${pc.dim('mcp-server →')} @codemcp/skills-mcp`);\n } else if (installMode === 'symlink') {\n if (universal.length > 0) {\n lines.push(` ${pc.green('universal:')} ${formatList(universal)}`);\n }\n if (symlinked.length > 0) {\n lines.push(` ${pc.dim('symlink →')} ${formatList(symlinked)}`);\n }\n } else {\n // Copy mode - all agents get copies\n const allNames = targetAgents.map((a) => agents[a].displayName);\n lines.push(` ${pc.dim('copy →')} ${formatList(allNames)}`);\n }\n\n return lines;\n}\n\n/**\n * Ensures universal agents are always included in the target agents list.\n * Used when -y flag is passed or when auto-selecting agents.\n */\nfunction ensureUniversalAgents(targetAgents: AgentType[]): AgentType[] {\n const universalAgents = getUniversalAgents();\n const result = [...targetAgents];\n\n for (const ua of universalAgents) {\n if (!result.includes(ua)) {\n result.push(ua);\n }\n }\n\n return result;\n}\n\n/**\n * Builds result lines from installation results, splitting by universal vs symlinked\n */\nfunction buildResultLines(\n results: Array<{\n agent: string;\n mode?: InstallMode;\n symlinkFailed?: boolean;\n }>,\n targetAgents: AgentType[]\n): string[] {\n const lines: string[] = [];\n\n // Check if this is MCP mode (check the mode field)\n const isMcpMode = results.length > 0 && results[0]!.mode === 'mcp-server';\n\n if (isMcpMode) {\n // MCP Server mode - show configuration instructions\n lines.push(` ${pc.dim('Important:')} Make sure your agent has configured`);\n lines.push(` ${pc.cyan('@codemcp/skills-mcp')} as MCP server.`);\n lines.push(` Then, the skill will automatically be picked up`);\n } else {\n // Split target agents by type\n const { universal, symlinked: symlinkAgents } = splitAgentsByType(targetAgents);\n\n // For symlink results, also track which ones actually succeeded vs failed\n const successfulSymlinks = results\n .filter((r) => !r.symlinkFailed && !universal.includes(r.agent))\n .map((r) => r.agent);\n const failedSymlinks = results.filter((r) => r.symlinkFailed).map((r) => r.agent);\n\n if (universal.length > 0) {\n lines.push(` ${pc.green('universal:')} ${formatList(universal)}`);\n }\n if (successfulSymlinks.length > 0) {\n lines.push(` ${pc.dim('symlinked:')} ${formatList(successfulSymlinks)}`);\n }\n if (failedSymlinks.length > 0) {\n lines.push(` ${pc.yellow('copied:')} ${formatList(failedSymlinks)}`);\n }\n }\n\n return lines;\n}\n\n/**\n * Wrapper around p.multiselect that adds a hint for keyboard usage.\n * Accepts options with required labels (matching our usage pattern).\n */\nfunction multiselect<Value>(opts: {\n message: string;\n options: Array<{ value: Value; label: string; hint?: string }>;\n initialValues?: Value[];\n required?: boolean;\n}) {\n return p.multiselect({\n ...opts,\n // Cast is safe: our options always have labels, which satisfies p.Option requirements\n options: opts.options as p.Option<Value>[],\n message: `${opts.message} ${pc.dim('(space to toggle)')}`,\n }) as Promise<Value[] | symbol>;\n}\n\n/**\n * Prompts the user to select agents using interactive search.\n * Pre-selects the last used agents if available.\n * Saves the selection for future use.\n */\nexport async function promptForAgents(\n message: string,\n choices: Array<{ value: AgentType; label: string; hint?: string }>\n): Promise<AgentType[] | symbol> {\n // Get last selected agents to pre-select\n let lastSelected: string[] | undefined;\n try {\n lastSelected = await getLastSelectedAgents();\n } catch {\n // Silently ignore errors reading lock file\n }\n\n const validAgents = choices.map((c) => c.value);\n\n // Default agents to pre-select when no valid history exists\n const defaultAgents: AgentType[] = ['claude-code', 'opencode', 'codex'];\n const defaultValues = defaultAgents.filter((a) => validAgents.includes(a));\n\n let initialValues: AgentType[] = [];\n\n if (lastSelected && lastSelected.length > 0) {\n // Filter stored agents against currently valid agents\n initialValues = lastSelected.filter((a) => validAgents.includes(a as AgentType)) as AgentType[];\n }\n\n // If no valid selection from history, use defaults\n if (initialValues.length === 0) {\n initialValues = defaultValues;\n }\n\n const selected = await searchMultiselect({\n message,\n items: choices,\n initialSelected: initialValues,\n required: true,\n });\n\n if (!isCancelled(selected)) {\n // Save selection for next time\n try {\n await saveSelectedAgents(selected as string[]);\n } catch {\n // Silently ignore errors writing lock file\n }\n }\n\n return selected as AgentType[] | symbol;\n}\n\n/**\n * Interactive agent selection using fuzzy search.\n * Shows universal agents as locked (always selected), and other agents as selectable.\n */\nasync function selectAgentsInteractive(options: {\n global?: boolean;\n}): Promise<AgentType[] | symbol> {\n // Filter out agents that don't support global installation when --global is used\n const supportsGlobalFilter = (a: AgentType) => !options.global || agents[a].globalSkillsDir;\n\n const universalAgents = getUniversalAgents().filter(supportsGlobalFilter);\n const otherAgents = getNonUniversalAgents().filter(supportsGlobalFilter);\n\n // Universal agents shown as locked section\n const universalSection = {\n title: 'Universal (.agentskills/skills)',\n items: universalAgents.map((a) => ({\n value: a,\n label: agents[a].displayName,\n })),\n };\n\n // Other agents are selectable with their skillsDir as hint\n const otherChoices = otherAgents.map((a) => ({\n value: a,\n label: agents[a].displayName,\n hint: options.global ? agents[a].globalSkillsDir! : agents[a].skillsDir,\n }));\n\n // Get last selected agents (filter to only non-universal ones for initial selection)\n let lastSelected: string[] | undefined;\n try {\n lastSelected = await getLastSelectedAgents();\n } catch {\n // Silently ignore errors\n }\n\n const initialSelected = lastSelected\n ? (lastSelected.filter(\n (a) => otherAgents.includes(a as AgentType) && !universalAgents.includes(a as AgentType)\n ) as AgentType[])\n : [];\n\n const selected = await searchMultiselect({\n message: 'Which agents do you want to install to?',\n items: otherChoices,\n initialSelected,\n lockedSection: universalSection,\n });\n\n if (!isCancelled(selected)) {\n // Save selection (all agents including universal)\n try {\n await saveSelectedAgents(selected as string[]);\n } catch {\n // Silently ignore errors\n }\n }\n\n return selected as AgentType[] | symbol;\n}\n\nconst version = packageJson.version;\nsetVersion(version);\n\nexport interface AddOptions {\n global?: boolean;\n agent?: string[];\n yes?: boolean;\n skill?: string[];\n list?: boolean;\n all?: boolean;\n fullDepth?: boolean;\n copy?: boolean;\n}\n\n/**\n * Handle remote skill installation from any supported host provider.\n * This is the generic handler for direct URL skills (Mintlify, HuggingFace, etc.)\n */\nasync function handleRemoteSkill(\n source: string,\n url: string,\n options: AddOptions,\n spinner: ReturnType<typeof p.spinner>\n): Promise<void> {\n // Find a provider that can handle this URL\n const provider = findProvider(url);\n\n if (!provider) {\n // Fall back to legacy Mintlify handling for backwards compatibility\n await handleDirectUrlSkillLegacy(source, url, options, spinner);\n return;\n }\n\n spinner.start(`Fetching skill.md from ${provider.displayName}...`);\n const providerSkill = await provider.fetchSkill(url);\n\n if (!providerSkill) {\n spinner.stop(pc.red('Invalid skill'));\n p.outro(\n pc.red('Could not fetch skill.md or missing required frontmatter (name, description).')\n );\n process.exit(1);\n }\n\n // Convert to RemoteSkill format with provider info\n const remoteSkill: RemoteSkill = {\n name: providerSkill.name,\n description: providerSkill.description,\n content: providerSkill.content,\n installName: providerSkill.installName,\n sourceUrl: providerSkill.sourceUrl,\n providerId: provider.id,\n sourceIdentifier: provider.getSourceIdentifier(url),\n metadata: providerSkill.metadata,\n };\n\n spinner.stop(`Found skill: ${pc.cyan(remoteSkill.installName)}`);\n\n p.log.info(`Skill: ${pc.cyan(remoteSkill.name)}`);\n p.log.message(pc.dim(remoteSkill.description));\n p.log.message(pc.dim(`Source: ${remoteSkill.sourceIdentifier}`));\n\n if (options.list) {\n console.log();\n p.log.step(pc.bold('Skill Details'));\n p.log.message(` ${pc.cyan('Name:')} ${remoteSkill.name}`);\n p.log.message(` ${pc.cyan('Install as:')} ${remoteSkill.installName}`);\n p.log.message(` ${pc.cyan('Provider:')} ${provider.displayName}`);\n p.log.message(` ${pc.cyan('Description:')} ${remoteSkill.description}`);\n console.log();\n p.outro('Run without --list to install');\n process.exit(0);\n }\n\n // Detect agents - universal agents are always included\n // MCP mode: install to canonical location, use universal agents only\n const universalAgents = getUniversalAgents();\n const targetAgents = universalAgents;\n\n let installGlobally = options.global ?? false;\n\n // Check if any selected agents support global installation\n const supportsGlobal = targetAgents.some((a) => agents[a].globalSkillsDir !== undefined);\n\n if (options.global === undefined && !options.yes && supportsGlobal) {\n const scope = await p.select({\n message: 'Installation scope',\n options: [\n {\n value: false,\n label: 'Project',\n hint: 'Install in current directory (committed with your project)',\n },\n {\n value: true,\n label: 'Global',\n hint: 'Install in home directory (available across all projects)',\n },\n ],\n });\n\n if (p.isCancel(scope)) {\n p.cancel('Installation cancelled');\n process.exit(0);\n }\n\n installGlobally = scope as boolean;\n }\n\n // MCP mode: always use MCP server installation\n const installMode: InstallMode = 'mcp-server';\n\n const cwd = process.cwd();\n\n // Check for overwrites (parallel)\n const overwriteChecks = await Promise.all(\n targetAgents.map(async (agent) => ({\n agent,\n installed: await isSkillInstalled(remoteSkill.installName, agent, {\n global: installGlobally,\n }),\n }))\n );\n const overwriteStatus = new Map(\n overwriteChecks.map(({ agent, installed }) => [agent, installed])\n );\n\n // Build installation summary\n const summaryLines: string[] = [];\n\n const canonicalPath = getCanonicalPath(remoteSkill.installName, { global: installGlobally });\n const shortCanonical = shortenPath(canonicalPath, cwd);\n summaryLines.push(`${pc.cyan(shortCanonical)}`);\n summaryLines.push(...buildAgentSummaryLines(targetAgents, installMode));\n\n const overwriteAgents = targetAgents\n .filter((a) => overwriteStatus.get(a))\n .map((a) => agents[a].displayName);\n\n if (overwriteAgents.length > 0) {\n summaryLines.push(` ${pc.yellow('overwrites:')} ${formatList(overwriteAgents)}`);\n }\n\n console.log();\n p.note(summaryLines.join('\\n'), 'Installation Summary');\n\n if (!options.yes) {\n const confirmed = await p.confirm({\n message: 'Proceed with installation?',\n });\n\n if (p.isCancel(confirmed) || !confirmed) {\n p.cancel('Installation cancelled');\n process.exit(0);\n }\n }\n\n spinner.start('Installing skill...');\n\n const results: {\n skill: string;\n agent: string;\n success: boolean;\n path: string;\n canonicalPath?: string;\n mode: InstallMode;\n symlinkFailed?: boolean;\n error?: string;\n }[] = [];\n\n if (installMode === 'mcp-server') {\n // MCP server mode: install once to canonical location, use universal agent\n const result = await installRemoteSkillForAgent(remoteSkill, 'universal', {\n global: installGlobally,\n mode: installMode,\n });\n results.push({\n skill: remoteSkill.installName,\n agent: 'MCP Server',\n ...result,\n });\n } else {\n // Symlink and copy modes: install per-agent\n for (const agent of targetAgents) {\n const result = await installRemoteSkillForAgent(remoteSkill, agent, {\n global: installGlobally,\n mode: installMode,\n });\n results.push({\n skill: remoteSkill.installName,\n agent: agents[agent].displayName,\n ...result,\n });\n }\n }\n\n spinner.stop('Installation complete');\n\n console.log();\n const successful = results.filter((r) => r.success);\n const failed = results.filter((r) => !r.success);\n\n // Track installation with provider-specific source identifier\n // Skip telemetry for private GitHub repos\n const isPrivate = await isSourcePrivate(remoteSkill.sourceIdentifier);\n if (isPrivate !== true) {\n // Only send telemetry if repo is public (isPrivate === false) or we can't determine (null for non-GitHub sources)\n track({\n event: 'install',\n source: remoteSkill.sourceIdentifier,\n skills: remoteSkill.installName,\n agents: targetAgents.join(','),\n ...(installGlobally && { global: '1' }),\n skillFiles: JSON.stringify({ [remoteSkill.installName]: url }),\n sourceType: remoteSkill.providerId,\n });\n }\n\n // Add to skill lock file for update tracking (only for global installs)\n if (successful.length > 0 && installGlobally) {\n try {\n // Try to fetch the folder hash from GitHub Trees API\n let skillFolderHash = '';\n if (remoteSkill.providerId === 'github') {\n const hash = await fetchSkillFolderHash(remoteSkill.sourceIdentifier, url);\n if (hash) skillFolderHash = hash;\n }\n\n await addSkillToLock(remoteSkill.installName, {\n source: remoteSkill.sourceIdentifier,\n sourceType: remoteSkill.providerId,\n sourceUrl: url,\n skillFolderHash,\n });\n } catch {\n // Don't fail installation if lock file update fails\n }\n }\n\n // Add to local lock file for project-scoped installs\n if (successful.length > 0 && !installGlobally) {\n try {\n const firstResult = successful[0]!;\n const installDir = firstResult.canonicalPath || firstResult.path;\n const computedHash = await computeSkillFolderHash(installDir);\n await addSkillToLocalLock(\n remoteSkill.installName,\n {\n source: remoteSkill.sourceIdentifier,\n sourceType: remoteSkill.providerId,\n computedHash,\n },\n cwd\n );\n } catch {\n // Don't fail installation if lock file update fails\n }\n }\n\n if (successful.length > 0) {\n const resultLines: string[] = [];\n const firstResult = successful[0]!;\n\n if (firstResult.mode === 'mcp-server') {\n // MCP server mode\n if (firstResult.canonicalPath) {\n const shortPath = shortenPath(firstResult.canonicalPath, cwd);\n resultLines.push(`${pc.green('✓')} ${shortPath}`);\n } else {\n resultLines.push(`${pc.green('✓')} ${remoteSkill.installName}`);\n }\n } else if (firstResult.mode === 'copy') {\n resultLines.push(`${pc.green('✓')} ${remoteSkill.installName} ${pc.dim('(copied)')}`);\n for (const r of successful) {\n const shortPath = shortenPath(r.path, cwd);\n resultLines.push(` ${pc.dim('→')} ${shortPath}`);\n }\n } else {\n // Symlink mode\n if (firstResult.canonicalPath) {\n const shortPath = shortenPath(firstResult.canonicalPath, cwd);\n resultLines.push(`${pc.green('✓')} ${shortPath}`);\n } else {\n resultLines.push(`${pc.green('✓')} ${remoteSkill.installName}`);\n }\n resultLines.push(...buildResultLines(successful, targetAgents));\n }\n\n const title = pc.green('Installed 1 skill');\n p.note(resultLines.join('\\n'), title);\n\n // Show MCP server configuration instructions\n if (firstResult.mode === 'mcp-server') {\n p.log.message('');\n p.log.message(pc.dim('To use with MCP clients, add to your MCP config:'));\n p.log.message(pc.cyan(' { \"command\": \"npx\", \"args\": [\"-y\", \"@codemcp/skills-mcp\"] }'));\n }\n\n // Show symlink failure warning\n const symlinkFailures = successful.filter((r) => r.mode === 'symlink' && r.symlinkFailed);\n if (symlinkFailures.length > 0) {\n const copiedAgentNames = symlinkFailures.map((r) => r.agent);\n p.log.warn(pc.yellow(`Symlinks failed for: ${formatList(copiedAgentNames)}`));\n p.log.message(\n pc.dim(\n ' Files were copied instead. On Windows, enable Developer Mode for symlink support.'\n )\n );\n }\n }\n\n if (failed.length > 0) {\n console.log();\n p.log.error(pc.red(`Failed to install ${failed.length}`));\n for (const r of failed) {\n p.log.message(` ${pc.red('✗')} ${r.skill} → ${r.agent}: ${pc.dim(r.error)}`);\n }\n }\n\n console.log();\n p.outro(\n pc.green('Done!') + pc.dim(' Review skills before use; they run with full agent permissions.')\n );\n\n // Prompt for find-skills after successful install\n await promptForFindSkills(options, targetAgents);\n}\n\n/**\n * Handle skills from a well-known endpoint (RFC 8615).\n * Discovers skills from /.well-known/skills/index.json\n */\nasync function handleWellKnownSkills(\n source: string,\n url: string,\n options: AddOptions,\n spinner: ReturnType<typeof p.spinner>\n): Promise<void> {\n spinner.start('Discovering skills from well-known endpoint...');\n\n // Fetch all skills from the well-known endpoint\n const skills = await wellKnownProvider.fetchAllSkills(url);\n\n if (skills.length === 0) {\n spinner.stop(pc.red('No skills found'));\n p.outro(\n pc.red(\n 'No skills found at this URL. Make sure the server has a /.well-known/skills/index.json file.'\n )\n );\n process.exit(1);\n }\n\n spinner.stop(`Found ${pc.green(skills.length)} skill${skills.length > 1 ? 's' : ''}`);\n\n // Log discovered skills\n for (const skill of skills) {\n p.log.info(`Skill: ${pc.cyan(skill.installName)}`);\n p.log.message(pc.dim(skill.description));\n if (skill.files.size > 1) {\n p.log.message(pc.dim(` Files: ${Array.from(skill.files.keys()).join(', ')}`));\n }\n }\n\n if (options.list) {\n console.log();\n p.log.step(pc.bold('Available Skills'));\n for (const skill of skills) {\n p.log.message(` ${pc.cyan(skill.installName)}`);\n p.log.message(` ${pc.dim(skill.description)}`);\n if (skill.files.size > 1) {\n p.log.message(` ${pc.dim(`Files: ${skill.files.size}`)}`);\n }\n }\n console.log();\n p.outro('Run without --list to install');\n process.exit(0);\n }\n\n // Filter skills if --skill option is provided\n let selectedSkills: WellKnownSkill[];\n\n if (options.skill?.includes('*')) {\n // --skill '*' selects all skills\n selectedSkills = skills;\n p.log.info(`Installing all ${skills.length} skills`);\n } else if (options.skill && options.skill.length > 0) {\n selectedSkills = skills.filter((s) =>\n options.skill!.some(\n (name) =>\n s.installName.toLowerCase() === name.toLowerCase() ||\n s.name.toLowerCase() === name.toLowerCase()\n )\n );\n\n if (selectedSkills.length === 0) {\n p.log.error(`No matching skills found for: ${options.skill.join(', ')}`);\n p.log.info('Available skills:');\n for (const s of skills) {\n p.log.message(` - ${s.installName}`);\n }\n process.exit(1);\n }\n } else if (skills.length === 1) {\n selectedSkills = skills;\n const firstSkill = skills[0]!;\n p.log.info(`Skill: ${pc.cyan(firstSkill.installName)}`);\n } else if (options.yes) {\n selectedSkills = skills;\n p.log.info(`Installing all ${skills.length} skills`);\n } else {\n // Prompt user to select skills\n const skillChoices = skills.map((s) => ({\n value: s,\n label: s.installName,\n hint: s.description.length > 60 ? s.description.slice(0, 57) + '...' : s.description,\n }));\n\n const selected = await multiselect({\n message: 'Select skills to install',\n options: skillChoices,\n required: true,\n });\n\n if (p.isCancel(selected)) {\n p.cancel('Installation cancelled');\n process.exit(0);\n }\n\n selectedSkills = selected as WellKnownSkill[];\n }\n\n // Detect agents\n let targetAgents: AgentType[];\n const validAgents = Object.keys(agents);\n\n if (options.agent?.includes('*')) {\n // --agent '*' selects all agents\n targetAgents = validAgents as AgentType[];\n p.log.info(`Installing to all ${targetAgents.length} agents`);\n } else if (options.agent && options.agent.length > 0) {\n const invalidAgents = options.agent.filter((a) => !validAgents.includes(a));\n\n if (invalidAgents.length > 0) {\n p.log.error(`Invalid agents: ${invalidAgents.join(', ')}`);\n p.log.info(`Valid agents: ${validAgents.join(', ')}`);\n process.exit(1);\n }\n\n targetAgents = options.agent as AgentType[];\n } else {\n spinner.start('Loading agents...');\n const installedAgents = await detectInstalledAgents();\n const totalAgents = Object.keys(agents).length;\n spinner.stop(`${totalAgents} agents`);\n\n if (installedAgents.length === 0) {\n if (options.yes) {\n targetAgents = validAgents as AgentType[];\n p.log.info('Installing to all agents');\n } else {\n p.log.info('Select agents to install skills to');\n\n const allAgentChoices = Object.entries(agents).map(([key, config]) => ({\n value: key as AgentType,\n label: config.displayName,\n }));\n\n // Use helper to prompt with search\n const selected = await promptForAgents(\n 'Which agents do you want to install to?',\n allAgentChoices\n );\n\n if (p.isCancel(selected)) {\n p.cancel('Installation cancelled');\n process.exit(0);\n }\n\n targetAgents = selected as AgentType[];\n }\n } else if (installedAgents.length === 1 || options.yes) {\n // Auto-select detected agents + ensure universal agents are included\n targetAgents = ensureUniversalAgents(installedAgents);\n if (installedAgents.length === 1) {\n const firstAgent = installedAgents[0]!;\n p.log.info(`Installing to: ${pc.cyan(agents[firstAgent].displayName)}`);\n } else {\n p.log.info(\n `Installing to: ${installedAgents.map((a) => pc.cyan(agents[a].displayName)).join(', ')}`\n );\n }\n } else {\n const selected = await selectAgentsInteractive({ global: options.global });\n\n if (p.isCancel(selected)) {\n p.cancel('Installation cancelled');\n process.exit(0);\n }\n\n targetAgents = selected as AgentType[];\n }\n }\n\n let installGlobally = options.global ?? false;\n\n // Check if any selected agents support global installation\n const supportsGlobal = targetAgents.some((a) => agents[a].globalSkillsDir !== undefined);\n\n if (options.global === undefined && !options.yes && supportsGlobal) {\n const scope = await p.select({\n message: 'Installation scope',\n options: [\n {\n value: false,\n label: 'Project',\n hint: 'Install in current directory (committed with your project)',\n },\n {\n value: true,\n label: 'Global',\n hint: 'Install in home directory (available across all projects)',\n },\n ],\n });\n\n if (p.isCancel(scope)) {\n p.cancel('Installation cancelled');\n process.exit(0);\n }\n\n installGlobally = scope as boolean;\n }\n\n // MCP mode: always use MCP server installation\n const installMode: InstallMode = 'mcp-server';\n\n const cwd = process.cwd();\n\n // Build installation summary\n const summaryLines: string[] = [];\n const agentNames = targetAgents.map((a) => agents[a].displayName);\n\n // Check if any skill will be overwritten (parallel)\n const overwriteChecks = await Promise.all(\n selectedSkills.flatMap((skill) =>\n targetAgents.map(async (agent) => ({\n skillName: skill.installName,\n agent,\n installed: await isSkillInstalled(skill.installName, agent, { global: installGlobally }),\n }))\n )\n );\n const overwriteStatus = new Map<string, Map<string, boolean>>();\n for (const { skillName, agent, installed } of overwriteChecks) {\n if (!overwriteStatus.has(skillName)) {\n overwriteStatus.set(skillName, new Map());\n }\n overwriteStatus.get(skillName)!.set(agent, installed);\n }\n\n for (const skill of selectedSkills) {\n if (summaryLines.length > 0) summaryLines.push('');\n\n const canonicalPath = getCanonicalPath(skill.installName, { global: installGlobally });\n const shortCanonical = shortenPath(canonicalPath, cwd);\n summaryLines.push(`${pc.cyan(shortCanonical)}`);\n summaryLines.push(...buildAgentSummaryLines(targetAgents, installMode));\n if (skill.files.size > 1) {\n summaryLines.push(` ${pc.dim('files:')} ${skill.files.size}`);\n }\n\n const skillOverwrites = overwriteStatus.get(skill.installName);\n const overwriteAgents = targetAgents\n .filter((a) => skillOverwrites?.get(a))\n .map((a) => agents[a].displayName);\n\n if (overwriteAgents.length > 0) {\n summaryLines.push(` ${pc.yellow('overwrites:')} ${formatList(overwriteAgents)}`);\n }\n }\n\n console.log();\n p.note(summaryLines.join('\\n'), 'Installation Summary');\n\n if (!options.yes) {\n const confirmed = await p.confirm({ message: 'Proceed with installation?' });\n\n if (p.isCancel(confirmed) || !confirmed) {\n p.cancel('Installation cancelled');\n process.exit(0);\n }\n }\n\n spinner.start('Installing skills...');\n\n const results: {\n skill: string;\n agent: string;\n success: boolean;\n path: string;\n canonicalPath?: string;\n mode: InstallMode;\n symlinkFailed?: boolean;\n error?: string;\n }[] = [];\n\n for (const skill of selectedSkills) {\n for (const agent of targetAgents) {\n const result = await installWellKnownSkillForAgent(skill, agent, {\n global: installGlobally,\n mode: installMode,\n });\n results.push({\n skill: skill.installName,\n agent: agents[agent].displayName,\n ...result,\n });\n }\n }\n\n spinner.stop('Installation complete');\n\n console.log();\n const successful = results.filter((r) => r.success);\n const failed = results.filter((r) => !r.success);\n\n // Track installation\n const sourceIdentifier = wellKnownProvider.getSourceIdentifier(url);\n\n // Build skillFiles map: { skillName: sourceUrl }\n const skillFiles: Record<string, string> = {};\n for (const skill of selectedSkills) {\n skillFiles[skill.installName] = skill.sourceUrl;\n }\n\n // Skip telemetry for private GitHub repos\n const isPrivate = await isSourcePrivate(sourceIdentifier);\n if (isPrivate !== true) {\n // Only send telemetry if repo is public (isPrivate === false) or we can't determine (null for non-GitHub sources)\n track({\n event: 'install',\n source: sourceIdentifier,\n skills: selectedSkills.map((s) => s.installName).join(','),\n agents: targetAgents.join(','),\n ...(installGlobally && { global: '1' }),\n skillFiles: JSON.stringify(skillFiles),\n sourceType: 'well-known',\n });\n }\n\n // Add to skill lock file for update tracking (only for global installs)\n if (successful.length > 0 && installGlobally) {\n const successfulSkillNames = new Set(successful.map((r) => r.skill));\n for (const skill of selectedSkills) {\n if (successfulSkillNames.has(skill.installName)) {\n try {\n await addSkillToLock(skill.installName, {\n source: sourceIdentifier,\n sourceType: 'well-known',\n sourceUrl: skill.sourceUrl,\n skillFolderHash: '', // Well-known skills don't have a folder hash\n });\n } catch {\n // Don't fail installation if lock file update fails\n }\n }\n }\n }\n\n // Add to local lock file for project-scoped installs\n if (successful.length > 0 && !installGlobally) {\n const successfulSkillNames = new Set(successful.map((r) => r.skill));\n for (const skill of selectedSkills) {\n if (successfulSkillNames.has(skill.installName)) {\n try {\n const matchingResult = successful.find((r) => r.skill === skill.installName);\n const installDir = matchingResult?.canonicalPath || matchingResult?.path;\n if (installDir) {\n const computedHash = await computeSkillFolderHash(installDir);\n await addSkillToLocalLock(\n skill.installName,\n {\n source: sourceIdentifier,\n sourceType: 'well-known',\n computedHash,\n },\n cwd\n );\n }\n } catch {\n // Don't fail installation if lock file update fails\n }\n }\n }\n }\n\n if (successful.length > 0) {\n const bySkill = new Map<string, typeof results>();\n for (const r of successful) {\n const skillResults = bySkill.get(r.skill) || [];\n skillResults.push(r);\n bySkill.set(r.skill, skillResults);\n }\n\n const skillCount = bySkill.size;\n const symlinkFailures = successful.filter((r) => r.mode === 'symlink' && r.symlinkFailed);\n const copiedAgents = symlinkFailures.map((r) => r.agent);\n const resultLines: string[] = [];\n\n for (const [skillName, skillResults] of bySkill) {\n const firstResult = skillResults[0]!;\n\n if (firstResult.mode === 'copy') {\n // Copy mode: show skill name and list all agent paths\n resultLines.push(`${pc.green('✓')} ${skillName} ${pc.dim('(copied)')}`);\n for (const r of skillResults) {\n const shortPath = shortenPath(r.path, cwd);\n resultLines.push(` ${pc.dim('→')} ${shortPath}`);\n }\n } else {\n // Symlink mode: show canonical path and universal/symlinked agents\n if (firstResult.canonicalPath) {\n const shortPath = shortenPath(firstResult.canonicalPath, cwd);\n resultLines.push(`${pc.green('✓')} ${shortPath}`);\n } else {\n resultLines.push(`${pc.green('✓')} ${skillName}`);\n }\n resultLines.push(...buildResultLines(skillResults, targetAgents));\n }\n }\n\n const title = pc.green(`Installed ${skillCount} skill${skillCount !== 1 ? 's' : ''}`);\n p.note(resultLines.join('\\n'), title);\n\n // Show symlink failure warning (only for symlink mode)\n if (symlinkFailures.length > 0) {\n p.log.warn(pc.yellow(`Symlinks failed for: ${formatList(copiedAgents)}`));\n p.log.message(\n pc.dim(\n ' Files were copied instead. On Windows, enable Developer Mode for symlink support.'\n )\n );\n }\n }\n\n if (failed.length > 0) {\n console.log();\n p.log.error(pc.red(`Failed to install ${failed.length}`));\n for (const r of failed) {\n p.log.message(` ${pc.red('✗')} ${r.skill} → ${r.agent}: ${pc.dim(r.error)}`);\n }\n }\n\n console.log();\n p.outro(\n pc.green('Done!') + pc.dim(' Review skills before use; they run with full agent permissions.')\n );\n\n // Prompt for find-skills after successful install\n await promptForFindSkills(options, targetAgents);\n}\n\n/**\n * Legacy handler for direct URL skill installation (Mintlify-hosted skills)\n * @deprecated Use handleRemoteSkill with provider system instead\n */\nasync function handleDirectUrlSkillLegacy(\n source: string,\n url: string,\n options: AddOptions,\n spinner: ReturnType<typeof p.spinner>\n): Promise<void> {\n spinner.start('Fetching skill.md...');\n const mintlifySkill = await fetchMintlifySkill(url);\n\n if (!mintlifySkill) {\n spinner.stop(pc.red('Invalid skill'));\n p.outro(\n pc.red(\n 'Could not fetch skill.md or missing required frontmatter (name, description, mintlify-proj).'\n )\n );\n process.exit(1);\n }\n\n // Convert to RemoteSkill and use the new handler\n const remoteSkill: RemoteSkill = {\n name: mintlifySkill.name,\n description: mintlifySkill.description,\n content: mintlifySkill.content,\n installName: mintlifySkill.mintlifySite,\n sourceUrl: mintlifySkill.sourceUrl,\n providerId: 'mintlify',\n sourceIdentifier: 'mintlify/com',\n };\n\n spinner.stop(`Found skill: ${pc.cyan(remoteSkill.installName)}`);\n\n p.log.info(`Skill: ${pc.cyan(remoteSkill.name)}`);\n p.log.message(pc.dim(remoteSkill.description));\n\n if (options.list) {\n console.log();\n p.log.step(pc.bold('Skill Details'));\n p.log.message(` ${pc.cyan('Name:')} ${remoteSkill.name}`);\n p.log.message(` ${pc.cyan('Site:')} ${remoteSkill.installName}`);\n p.log.message(` ${pc.cyan('Description:')} ${remoteSkill.description}`);\n console.log();\n p.outro('Run without --list to install');\n process.exit(0);\n }\n\n // Detect agents\n let targetAgents: AgentType[];\n const validAgents = Object.keys(agents);\n\n if (options.agent?.includes('*')) {\n // --agent '*' selects all agents\n targetAgents = validAgents as AgentType[];\n p.log.info(`Installing to all ${targetAgents.length} agents`);\n } else if (options.agent && options.agent.length > 0) {\n const invalidAgents = options.agent.filter((a) => !validAgents.includes(a));\n\n if (invalidAgents.length > 0) {\n p.log.error(`Invalid agents: ${invalidAgents.join(', ')}`);\n p.log.info(`Valid agents: ${validAgents.join(', ')}`);\n process.exit(1);\n }\n\n targetAgents = options.agent as AgentType[];\n } else {\n spinner.start('Loading agents...');\n const installedAgents = await detectInstalledAgents();\n const totalAgents = Object.keys(agents).length;\n spinner.stop(`${totalAgents} agents`);\n\n if (installedAgents.length === 0) {\n if (options.yes) {\n targetAgents = validAgents as AgentType[];\n p.log.info('Installing to all agents');\n } else {\n p.log.info('Select agents to install skills to');\n\n const allAgentChoices = Object.entries(agents).map(([key, config]) => ({\n value: key as AgentType,\n label: config.displayName,\n }));\n\n // Use helper to prompt with search\n const selected = await promptForAgents(\n 'Which agents do you want to install to?',\n allAgentChoices\n );\n\n if (p.isCancel(selected)) {\n p.cancel('Installation cancelled');\n process.exit(0);\n }\n\n targetAgents = selected as AgentType[];\n }\n } else if (installedAgents.length === 1 || options.yes) {\n // Auto-select detected agents + ensure universal agents are included\n targetAgents = ensureUniversalAgents(installedAgents);\n if (installedAgents.length === 1) {\n const firstAgent = installedAgents[0]!;\n p.log.info(`Installing to: ${pc.cyan(agents[firstAgent].displayName)}`);\n } else {\n p.log.info(\n `Installing to: ${installedAgents.map((a) => pc.cyan(agents[a].displayName)).join(', ')}`\n );\n }\n } else {\n const selected = await selectAgentsInteractive({ global: options.global });\n\n if (p.isCancel(selected)) {\n p.cancel('Installation cancelled');\n process.exit(0);\n }\n\n targetAgents = selected as AgentType[];\n }\n }\n\n let installGlobally = options.global ?? false;\n\n // Check if any selected agents support global installation\n const supportsGlobal = targetAgents.some((a) => agents[a].globalSkillsDir !== undefined);\n\n if (options.global === undefined && !options.yes && supportsGlobal) {\n const scope = await p.select({\n message: 'Installation scope',\n options: [\n {\n value: false,\n label: 'Project',\n hint: 'Install in current directory (committed with your project)',\n },\n {\n value: true,\n label: 'Global',\n hint: 'Install in home directory (available across all projects)',\n },\n ],\n });\n\n if (p.isCancel(scope)) {\n p.cancel('Installation cancelled');\n process.exit(0);\n }\n\n installGlobally = scope as boolean;\n }\n\n // Use symlink mode by default for direct URL skills\n const installMode: InstallMode = 'symlink';\n const cwd = process.cwd();\n\n // Check for overwrites (parallel)\n const overwriteChecks = await Promise.all(\n targetAgents.map(async (agent) => ({\n agent,\n installed: await isSkillInstalled(remoteSkill.installName, agent, {\n global: installGlobally,\n }),\n }))\n );\n const overwriteStatus = new Map(\n overwriteChecks.map(({ agent, installed }) => [agent, installed])\n );\n\n // Build installation summary\n const summaryLines: string[] = [];\n const agentNames = targetAgents.map((a) => agents[a].displayName);\n const canonicalPath = getCanonicalPath(remoteSkill.installName, { global: installGlobally });\n const shortCanonical = shortenPath(canonicalPath, cwd);\n summaryLines.push(`${pc.cyan(shortCanonical)}`);\n summaryLines.push(...buildAgentSummaryLines(targetAgents, installMode));\n\n const overwriteAgents = targetAgents\n .filter((a) => overwriteStatus.get(a))\n .map((a) => agents[a].displayName);\n\n if (overwriteAgents.length > 0) {\n summaryLines.push(` ${pc.yellow('overwrites:')} ${formatList(overwriteAgents)}`);\n }\n\n console.log();\n p.note(summaryLines.join('\\n'), 'Installation Summary');\n\n if (!options.yes) {\n const confirmed = await p.confirm({\n message: 'Proceed with installation?',\n });\n\n if (p.isCancel(confirmed) || !confirmed) {\n p.cancel('Installation cancelled');\n process.exit(0);\n }\n }\n\n spinner.start('Installing skill...');\n\n const results: {\n skill: string;\n agent: string;\n success: boolean;\n path: string;\n canonicalPath?: string;\n mode: InstallMode;\n symlinkFailed?: boolean;\n error?: string;\n }[] = [];\n\n if (installMode === 'mcp-server') {\n // MCP server mode: install once to canonical location, use universal agent\n const result = await installRemoteSkillForAgent(remoteSkill, 'universal', {\n global: installGlobally,\n mode: installMode,\n });\n results.push({\n skill: remoteSkill.installName,\n agent: 'MCP Server',\n ...result,\n });\n } else {\n // Symlink and copy modes: install per-agent\n for (const agent of targetAgents) {\n const result = await installRemoteSkillForAgent(remoteSkill, agent, {\n global: installGlobally,\n mode: installMode,\n });\n results.push({\n skill: remoteSkill.installName,\n agent: agents[agent].displayName,\n ...result,\n });\n }\n }\n\n spinner.stop('Installation complete');\n\n console.log();\n const successful = results.filter((r) => r.success);\n const failed = results.filter((r) => !r.success);\n\n // Track installation\n // Skip telemetry for private GitHub repos (mintlify/com is not a GitHub repo, so always send)\n track({\n event: 'install',\n source: 'mintlify/com',\n skills: remoteSkill.installName,\n agents: targetAgents.join(','),\n ...(installGlobally && { global: '1' }),\n skillFiles: JSON.stringify({ [remoteSkill.installName]: url }),\n sourceType: 'mintlify',\n });\n\n // Add to skill lock file for update tracking (only for global installs)\n if (successful.length > 0 && installGlobally) {\n try {\n // skillFolderHash will be populated by telemetry server\n // Mintlify skills are single-file, so folder hash = content hash on server\n await addSkillToLock(remoteSkill.installName, {\n source: `mintlify/${remoteSkill.installName}`,\n sourceType: 'mintlify',\n sourceUrl: url,\n skillFolderHash: '', // Populated by server\n });\n } catch {\n // Don't fail installation if lock file update fails\n }\n }\n\n if (successful.length > 0) {\n const resultLines: string[] = [];\n const firstResult = successful[0]!;\n\n if (firstResult.canonicalPath) {\n const shortPath = shortenPath(firstResult.canonicalPath, cwd);\n resultLines.push(`${pc.green('✓')} ${shortPath}`);\n } else {\n resultLines.push(`${pc.green('✓')} ${remoteSkill.installName}`);\n }\n resultLines.push(...buildResultLines(successful, targetAgents));\n\n const title = pc.green('Installed 1 skill');\n p.note(resultLines.join('\\n'), title);\n\n // Show symlink failure warning\n const symlinkFailures = successful.filter((r) => r.mode === 'symlink' && r.symlinkFailed);\n if (symlinkFailures.length > 0) {\n const copiedAgentNames = symlinkFailures.map((r) => r.agent);\n p.log.warn(pc.yellow(`Symlinks failed for: ${formatList(copiedAgentNames)}`));\n p.log.message(\n pc.dim(\n ' Files were copied instead. On Windows, enable Developer Mode for symlink support.'\n )\n );\n }\n }\n\n if (failed.length > 0) {\n console.log();\n p.log.error(pc.red(`Failed to install ${failed.length}`));\n for (const r of failed) {\n p.log.message(` ${pc.red('✗')} ${r.skill} → ${r.agent}: ${pc.dim(r.error)}`);\n }\n }\n\n console.log();\n p.outro(\n pc.green('Done!') + pc.dim(' Review skills before use; they run with full agent permissions.')\n );\n\n // Prompt for find-skills after successful install\n await promptForFindSkills(options, targetAgents);\n}\n\nexport async function runAdd(args: string[], options: AddOptions = {}): Promise<void> {\n const source = args[0];\n let installTipShown = false;\n\n const showInstallTip = (): void => {\n if (installTipShown) return;\n p.log.message(\n pc.dim('Tip: use the --yes (-y) and --global (-g) flags to install without prompts.')\n );\n installTipShown = true;\n };\n\n if (!source) {\n console.log();\n console.log(\n pc.bgRed(pc.white(pc.bold(' ERROR '))) + ' ' + pc.red('Missing required argument: source')\n );\n console.log();\n console.log(pc.dim(' Usage:'));\n console.log(` ${pc.cyan('npx skills add')} ${pc.yellow('<source>')} ${pc.dim('[options]')}`);\n console.log();\n console.log(pc.dim(' Example:'));\n console.log(` ${pc.cyan('npx skills add')} ${pc.yellow('vercel-labs/agent-skills')}`);\n console.log();\n process.exit(1);\n }\n\n // --all implies --skill '*' and --agent '*' and -y\n if (options.all) {\n options.skill = ['*'];\n options.agent = ['*'];\n options.yes = true;\n }\n\n console.log();\n p.intro(pc.bgCyan(pc.black(' skills ')));\n\n if (!process.stdin.isTTY) {\n showInstallTip();\n }\n\n let tempDir: string | null = null;\n\n try {\n const spinner = p.spinner();\n\n spinner.start('Parsing source...');\n const parsed = parseSource(source);\n spinner.stop(\n `Source: ${parsed.type === 'local' ? parsed.localPath! : parsed.url}${parsed.ref ? ` @ ${pc.yellow(parsed.ref)}` : ''}${parsed.subpath ? ` (${parsed.subpath})` : ''}${parsed.skillFilter ? ` ${pc.dim('@')}${pc.cyan(parsed.skillFilter)}` : ''}`\n );\n\n // Handle direct URL skills (Mintlify, HuggingFace, etc.) via provider system\n if (parsed.type === 'direct-url') {\n await handleRemoteSkill(source, parsed.url, options, spinner);\n return;\n }\n\n // Handle well-known skills from arbitrary URLs\n if (parsed.type === 'well-known') {\n await handleWellKnownSkills(source, parsed.url, options, spinner);\n return;\n }\n\n let skillsDir: string;\n\n if (parsed.type === 'local') {\n // Use local path directly, no cloning needed\n spinner.start('Validating local path...');\n if (!existsSync(parsed.localPath!)) {\n spinner.stop(pc.red('Path not found'));\n p.outro(pc.red(`Local path does not exist: ${parsed.localPath}`));\n process.exit(1);\n }\n skillsDir = parsed.localPath!;\n spinner.stop('Local path validated');\n } else {\n // Clone repository for remote sources\n spinner.start('Cloning repository...');\n tempDir = await cloneRepo(parsed.url, parsed.ref);\n skillsDir = tempDir;\n spinner.stop('Repository cloned');\n }\n\n // If skillFilter is present from @skill syntax (e.g., owner/repo@skill-name),\n // merge it into options.skill\n if (parsed.skillFilter) {\n options.skill = options.skill || [];\n if (!options.skill.includes(parsed.skillFilter)) {\n options.skill.push(parsed.skillFilter);\n }\n }\n\n // Include internal skills when a specific skill is explicitly requested\n // (via --skill or @skill syntax)\n const includeInternal = !!(options.skill && options.skill.length > 0);\n\n spinner.start('Discovering skills...');\n const skills = await discoverSkills(skillsDir, parsed.subpath, {\n includeInternal,\n fullDepth: options.fullDepth,\n });\n\n if (skills.length === 0) {\n spinner.stop(pc.red('No skills found'));\n p.outro(\n pc.red('No valid skills found. Skills require a SKILL.md with name and description.')\n );\n await cleanup(tempDir);\n process.exit(1);\n }\n\n spinner.stop(`Found ${pc.green(skills.length)} skill${skills.length > 1 ? 's' : ''}`);\n\n if (options.list) {\n console.log();\n p.log.step(pc.bold('Available Skills'));\n\n // Group available skills by plugin for list output\n const groupedSkills: Record<string, Skill[]> = {};\n const ungroupedSkills: Skill[] = [];\n\n for (const skill of skills) {\n if (skill.pluginName) {\n const group = skill.pluginName;\n if (!groupedSkills[group]) groupedSkills[group] = [];\n groupedSkills[group].push(skill);\n } else {\n ungroupedSkills.push(skill);\n }\n }\n\n // Print groups\n const sortedGroups = Object.keys(groupedSkills).sort();\n for (const group of sortedGroups) {\n // Convert kebab-case to Title Case for display header\n const title = group\n .split('-')\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1))\n .join(' ');\n\n console.log(pc.bold(title));\n for (const skill of groupedSkills[group]!) {\n p.log.message(` ${pc.cyan(getSkillDisplayName(skill))}`);\n p.log.message(` ${pc.dim(skill.description)}`);\n }\n console.log();\n }\n\n // Print ungrouped\n if (ungroupedSkills.length > 0) {\n if (sortedGroups.length > 0) console.log(pc.bold('General'));\n for (const skill of ungroupedSkills) {\n p.log.message(` ${pc.cyan(getSkillDisplayName(skill))}`);\n p.log.message(` ${pc.dim(skill.description)}`);\n }\n }\n\n console.log();\n p.outro('Use --skill <name> to install specific skills');\n await cleanup(tempDir);\n process.exit(0);\n }\n\n let selectedSkills: Skill[];\n\n if (options.skill?.includes('*')) {\n // --skill '*' selects all skills\n selectedSkills = skills;\n p.log.info(`Installing all ${skills.length} skills`);\n } else if (options.skill && options.skill.length > 0) {\n selectedSkills = filterSkills(skills, options.skill);\n\n if (selectedSkills.length === 0) {\n p.log.error(`No matching skills found for: ${options.skill.join(', ')}`);\n p.log.info('Available skills:');\n for (const s of skills) {\n p.log.message(` - ${getSkillDisplayName(s)}`);\n }\n await cleanup(tempDir);\n process.exit(1);\n }\n\n p.log.info(\n `Selected ${selectedSkills.length} skill${selectedSkills.length !== 1 ? 's' : ''}: ${selectedSkills.map((s) => pc.cyan(getSkillDisplayName(s))).join(', ')}`\n );\n } else if (skills.length === 1) {\n selectedSkills = skills;\n const firstSkill = skills[0]!;\n p.log.info(`Skill: ${pc.cyan(getSkillDisplayName(firstSkill))}`);\n p.log.message(pc.dim(firstSkill.description));\n } else if (options.yes) {\n selectedSkills = skills;\n p.log.info(`Installing all ${skills.length} skills`);\n } else {\n // Sort skills by plugin name first, then by skill name\n const sortedSkills = [...skills].sort((a, b) => {\n if (a.pluginName && !b.pluginName) return -1;\n if (!a.pluginName && b.pluginName) return 1;\n if (a.pluginName && b.pluginName && a.pluginName !== b.pluginName) {\n return a.pluginName.localeCompare(b.pluginName);\n }\n return getSkillDisplayName(a).localeCompare(getSkillDisplayName(b));\n });\n\n // Check if any skills have plugin grouping\n const hasGroups = sortedSkills.some((s) => s.pluginName);\n\n let selected: Skill[] | symbol;\n\n if (hasGroups) {\n // Build grouped options for groupMultiselect\n const kebabToTitle = (s: string) =>\n s\n .split('-')\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1))\n .join(' ');\n\n const grouped: Record<string, p.Option<Skill>[]> = {};\n for (const s of sortedSkills) {\n const groupName = s.pluginName ? kebabToTitle(s.pluginName) : 'Other';\n if (!grouped[groupName]) grouped[groupName] = [];\n grouped[groupName]!.push({\n value: s,\n label: getSkillDisplayName(s),\n hint: s.description.length > 60 ? s.description.slice(0, 57) + '...' : s.description,\n });\n }\n\n selected = await p.groupMultiselect({\n message: `Select skills to install ${pc.dim('(space to toggle)')}`,\n options: grouped,\n required: true,\n });\n } else {\n const skillChoices = sortedSkills.map((s) => ({\n value: s,\n label: getSkillDisplayName(s),\n hint: s.description.length > 60 ? s.description.slice(0, 57) + '...' : s.description,\n }));\n\n selected = await multiselect({\n message: 'Select skills to install',\n options: skillChoices,\n required: true,\n });\n }\n\n if (p.isCancel(selected)) {\n p.cancel('Installation cancelled');\n await cleanup(tempDir);\n process.exit(0);\n }\n\n selectedSkills = selected as Skill[];\n }\n\n // Kick off security audit fetch early (non-blocking) so it runs\n // in parallel with agent selection, scope, and mode prompts.\n const ownerRepoForAudit = getOwnerRepo(parsed);\n const auditPromise = ownerRepoForAudit\n ? fetchAuditData(\n ownerRepoForAudit,\n selectedSkills.map((s) => getSkillDisplayName(s))\n )\n : Promise.resolve(null);\n\n // MCP mode: install to canonical location, use universal agents only\n const targetAgents = getUniversalAgents();\n\n let installGlobally = options.global ?? false;\n\n // Check if any selected agents support global installation\n const supportsGlobal = targetAgents.some((a) => agents[a].globalSkillsDir !== undefined);\n\n if (options.global === undefined && !options.yes && supportsGlobal) {\n const scope = await p.select({\n message: 'Installation scope',\n options: [\n {\n value: false,\n label: 'Project',\n hint: 'Install in current directory (committed with your project)',\n },\n {\n value: true,\n label: 'Global',\n hint: 'Install in home directory (available across all projects)',\n },\n ],\n });\n\n if (p.isCancel(scope)) {\n p.cancel('Installation cancelled');\n await cleanup(tempDir);\n process.exit(0);\n }\n\n installGlobally = scope as boolean;\n }\n\n // MCP mode: always use MCP server installation\n const installMode: InstallMode = 'mcp-server';\n\n const cwd = process.cwd();\n\n // Build installation summary\n const summaryLines: string[] = [];\n const agentNames = targetAgents.map((a) => agents[a].displayName);\n\n // Check if any skill will be overwritten (parallel)\n const overwriteChecks = await Promise.all(\n selectedSkills.flatMap((skill) =>\n targetAgents.map(async (agent) => ({\n skillName: skill.name,\n agent,\n installed: await isSkillInstalled(skill.name, agent, { global: installGlobally }),\n }))\n )\n );\n const overwriteStatus = new Map<string, Map<string, boolean>>();\n for (const { skillName, agent, installed } of overwriteChecks) {\n if (!overwriteStatus.has(skillName)) {\n overwriteStatus.set(skillName, new Map());\n }\n overwriteStatus.get(skillName)!.set(agent, installed);\n }\n\n // Group selected skills for summary\n const groupedSummary: Record<string, Skill[]> = {};\n const ungroupedSummary: Skill[] = [];\n\n for (const skill of selectedSkills) {\n if (skill.pluginName) {\n const group = skill.pluginName;\n if (!groupedSummary[group]) groupedSummary[group] = [];\n groupedSummary[group].push(skill);\n } else {\n ungroupedSummary.push(skill);\n }\n }\n\n // Helper to print summary lines for a list of skills\n const printSkillSummary = (skills: Skill[]) => {\n for (const skill of skills) {\n if (summaryLines.length > 0) summaryLines.push('');\n\n const canonicalPath = getCanonicalPath(skill.name, { global: installGlobally });\n const shortCanonical = shortenPath(canonicalPath, cwd);\n summaryLines.push(`${pc.cyan(shortCanonical)}`);\n summaryLines.push(...buildAgentSummaryLines(targetAgents, installMode));\n\n const skillOverwrites = overwriteStatus.get(skill.name);\n const overwriteAgents = targetAgents\n .filter((a) => skillOverwrites?.get(a))\n .map((a) => agents[a].displayName);\n\n if (overwriteAgents.length > 0) {\n summaryLines.push(` ${pc.yellow('overwrites:')} ${formatList(overwriteAgents)}`);\n }\n }\n };\n\n // Build grouped summary\n const sortedGroups = Object.keys(groupedSummary).sort();\n\n for (const group of sortedGroups) {\n const title = group\n .split('-')\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1))\n .join(' ');\n\n summaryLines.push('');\n summaryLines.push(pc.bold(title));\n printSkillSummary(groupedSummary[group]!);\n }\n\n if (ungroupedSummary.length > 0) {\n if (sortedGroups.length > 0) {\n summaryLines.push('');\n summaryLines.push(pc.bold('General'));\n }\n printSkillSummary(ungroupedSummary);\n }\n\n console.log();\n p.note(summaryLines.join('\\n'), 'Installation Summary');\n\n // Await and display security audit results (started earlier in parallel)\n // Wrapped in try/catch so a failed audit fetch never blocks installation.\n try {\n const auditData = await auditPromise;\n if (auditData && ownerRepoForAudit) {\n const securityLines = buildSecurityLines(\n auditData,\n selectedSkills.map((s) => ({\n slug: getSkillDisplayName(s),\n displayName: getSkillDisplayName(s),\n })),\n ownerRepoForAudit\n );\n if (securityLines.length > 0) {\n p.note(securityLines.join('\\n'), 'Security Risk Assessments');\n }\n }\n } catch {\n // Silently skip — security info is advisory only\n }\n\n if (!options.yes) {\n const confirmed = await p.confirm({ message: 'Proceed with installation?' });\n\n if (p.isCancel(confirmed) || !confirmed) {\n p.cancel('Installation cancelled');\n await cleanup(tempDir);\n process.exit(0);\n }\n }\n\n spinner.start('Installing skills...');\n\n const results: {\n skill: string;\n agent: string;\n success: boolean;\n path: string;\n canonicalPath?: string;\n mode: InstallMode;\n symlinkFailed?: boolean;\n error?: string;\n pluginName?: string;\n }[] = [];\n\n for (const skill of selectedSkills) {\n for (const agent of targetAgents) {\n const result = await installSkillForAgent(skill, agent, {\n global: installGlobally,\n mode: installMode,\n });\n results.push({\n skill: getSkillDisplayName(skill),\n agent: agents[agent].displayName,\n pluginName: skill.pluginName,\n ...result,\n });\n }\n }\n\n spinner.stop('Installation complete');\n\n console.log();\n const successful = results.filter((r) => r.success);\n const failed = results.filter((r) => !r.success);\n\n // Track installation result\n // Build skillFiles map: { skillName: relative path to SKILL.md from repo root }\n const skillFiles: Record<string, string> = {};\n for (const skill of selectedSkills) {\n // skill.path is absolute, compute relative from tempDir (repo root)\n let relativePath: string;\n if (tempDir && skill.path === tempDir) {\n // Skill is at root level of repo\n relativePath = 'SKILL.md';\n } else if (tempDir && skill.path.startsWith(tempDir + sep)) {\n // Compute path relative to repo root (tempDir), not search path\n // Use forward slashes for telemetry (URL-style paths)\n relativePath =\n skill.path\n .slice(tempDir.length + 1)\n .split(sep)\n .join('/') + '/SKILL.md';\n } else {\n // Local path - skip telemetry for local installs\n continue;\n }\n skillFiles[skill.name] = relativePath;\n }\n\n // Normalize source to owner/repo format for telemetry\n const normalizedSource = getOwnerRepo(parsed);\n\n // Only track if we have a valid remote source and it's not a private repo\n if (normalizedSource) {\n const ownerRepo = parseOwnerRepo(normalizedSource);\n if (ownerRepo) {\n // Check if repo is private - skip telemetry for private repos\n const isPrivate = await isRepoPrivate(ownerRepo.owner, ownerRepo.repo);\n // Only send telemetry if repo is public (isPrivate === false)\n // If we can't determine (null), err on the side of caution and skip telemetry\n if (isPrivate === false) {\n track({\n event: 'install',\n source: normalizedSource,\n skills: selectedSkills.map((s) => s.name).join(','),\n agents: targetAgents.join(','),\n ...(installGlobally && { global: '1' }),\n skillFiles: JSON.stringify(skillFiles),\n });\n }\n } else {\n // If we can't parse owner/repo, still send telemetry (for non-GitHub sources)\n track({\n event: 'install',\n source: normalizedSource,\n skills: selectedSkills.map((s) => s.name).join(','),\n agents: targetAgents.join(','),\n ...(installGlobally && { global: '1' }),\n skillFiles: JSON.stringify(skillFiles),\n });\n }\n }\n\n // Add to skill lock file for update tracking (only for global installs)\n if (successful.length > 0 && installGlobally && normalizedSource) {\n const successfulSkillNames = new Set(successful.map((r) => r.skill));\n for (const skill of selectedSkills) {\n const skillDisplayName = getSkillDisplayName(skill);\n if (successfulSkillNames.has(skillDisplayName)) {\n try {\n // Fetch the folder hash from GitHub Trees API\n let skillFolderHash = '';\n const skillPathValue = skillFiles[skill.name];\n if (parsed.type === 'github' && skillPathValue) {\n const hash = await fetchSkillFolderHash(normalizedSource, skillPathValue);\n if (hash) skillFolderHash = hash;\n }\n\n await addSkillToLock(skill.name, {\n source: normalizedSource,\n sourceType: parsed.type,\n sourceUrl: parsed.url,\n skillPath: skillPathValue,\n skillFolderHash,\n pluginName: skill.pluginName,\n });\n } catch {\n // Don't fail installation if lock file update fails\n }\n }\n }\n }\n\n // Add to local lock file for project-scoped installs\n if (successful.length > 0 && !installGlobally) {\n const successfulSkillNames = new Set(successful.map((r) => r.skill));\n for (const skill of selectedSkills) {\n const skillDisplayName = getSkillDisplayName(skill);\n if (successfulSkillNames.has(skillDisplayName)) {\n try {\n const computedHash = await computeSkillFolderHash(skill.path);\n await addSkillToLocalLock(\n skill.name,\n {\n source: normalizedSource || parsed.url,\n sourceType: parsed.type,\n computedHash,\n },\n cwd\n );\n } catch {\n // Don't fail installation if lock file update fails\n }\n }\n }\n }\n\n if (successful.length > 0) {\n const bySkill = new Map<string, typeof results>();\n\n // Group results by plugin name\n const groupedResults: Record<string, typeof results> = {};\n const ungroupedResults: typeof results = [];\n\n for (const r of successful) {\n const skillResults = bySkill.get(r.skill) || [];\n skillResults.push(r);\n bySkill.set(r.skill, skillResults);\n\n // We only need to group once per skill (take the first result for that skill)\n if (skillResults.length === 1) {\n if (r.pluginName) {\n const group = r.pluginName;\n if (!groupedResults[group]) groupedResults[group] = [];\n // We'll store just one entry per skill here to drive the loop\n groupedResults[group].push(r);\n } else {\n ungroupedResults.push(r);\n }\n }\n }\n\n const skillCount = bySkill.size;\n const symlinkFailures = successful.filter((r) => r.mode === 'symlink' && r.symlinkFailed);\n const copiedAgents = symlinkFailures.map((r) => r.agent);\n const resultLines: string[] = [];\n\n const printSkillResults = (entries: typeof results) => {\n for (const entry of entries) {\n const skillResults = bySkill.get(entry.skill) || [];\n const firstResult = skillResults[0]!;\n\n if (firstResult.mode === 'copy') {\n // Copy mode: show skill name and list all agent paths\n resultLines.push(`${pc.green('✓')} ${entry.skill} ${pc.dim('(copied)')}`);\n for (const r of skillResults) {\n const shortPath = shortenPath(r.path, cwd);\n resultLines.push(` ${pc.dim('→')} ${shortPath}`);\n }\n } else {\n // Symlink mode: show canonical path and universal/symlinked agents\n if (firstResult.canonicalPath) {\n const shortPath = shortenPath(firstResult.canonicalPath, cwd);\n resultLines.push(`${pc.green('✓')} ${shortPath}`);\n } else {\n resultLines.push(`${pc.green('✓')} ${entry.skill}`);\n }\n resultLines.push(...buildResultLines(skillResults, targetAgents));\n }\n }\n };\n\n // Print grouped results\n const sortedResultGroups = Object.keys(groupedResults).sort();\n\n for (const group of sortedResultGroups) {\n const title = group\n .split('-')\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1))\n .join(' ');\n\n resultLines.push('');\n resultLines.push(pc.bold(title));\n printSkillResults(groupedResults[group]!);\n }\n\n if (ungroupedResults.length > 0) {\n if (sortedResultGroups.length > 0) {\n resultLines.push('');\n resultLines.push(pc.bold('General'));\n }\n printSkillResults(ungroupedResults);\n }\n\n const title = pc.green(`Installed ${skillCount} skill${skillCount !== 1 ? 's' : ''}`);\n p.note(resultLines.join('\\n'), title);\n\n // Show symlink failure warning (only for symlink mode)\n if (symlinkFailures.length > 0) {\n p.log.warn(pc.yellow(`Symlinks failed for: ${formatList(copiedAgents)}`));\n p.log.message(\n pc.dim(\n ' Files were copied instead. On Windows, enable Developer Mode for symlink support.'\n )\n );\n }\n }\n\n if (failed.length > 0) {\n console.log();\n p.log.error(pc.red(`Failed to install ${failed.length}`));\n for (const r of failed) {\n p.log.message(` ${pc.red('✗')} ${r.skill} → ${r.agent}: ${pc.dim(r.error)}`);\n }\n }\n\n console.log();\n p.outro(\n pc.green('Done!') +\n pc.dim(' Review skills before use; they run with full agent permissions.')\n );\n\n // Prompt for find-skills after successful install\n await promptForFindSkills(options, targetAgents);\n } catch (error) {\n if (error instanceof GitCloneError) {\n p.log.error(pc.red('Failed to clone repository'));\n // Print each line of the error message separately for better formatting\n for (const line of error.message.split('\\n')) {\n p.log.message(pc.dim(line));\n }\n } else {\n p.log.error(error instanceof Error ? error.message : 'Unknown error occurred');\n }\n showInstallTip();\n p.outro(pc.red('Installation failed'));\n process.exit(1);\n } finally {\n await cleanup(tempDir);\n }\n}\n\n// Cleanup helper\nasync function cleanup(tempDir: string | null) {\n if (tempDir) {\n try {\n await cleanupTempDir(tempDir);\n } catch {\n // Ignore cleanup errors\n }\n }\n}\n\n/**\n * Prompt user to install the find-skills skill after their first installation.\n */\nasync function promptForFindSkills(\n options?: AddOptions,\n targetAgents?: AgentType[]\n): Promise<void> {\n // Skip if already dismissed or not in interactive mode\n if (!process.stdin.isTTY) return;\n if (options?.yes) return;\n\n try {\n const dismissed = await isPromptDismissed('findSkillsPrompt');\n if (dismissed) return;\n\n // Check if find-skills is already installed\n const findSkillsInstalled = await isSkillInstalled('find-skills', 'claude-code', {\n global: true,\n });\n if (findSkillsInstalled) {\n // Mark as dismissed so we don't check again\n await dismissPrompt('findSkillsPrompt');\n return;\n }\n\n console.log();\n p.log.message(pc.dim(\"One-time prompt - you won't be asked again if you dismiss.\"));\n const install = await p.confirm({\n message: `Install the ${pc.cyan('find-skills')} skill? It helps your agent discover and suggest skills.`,\n });\n\n if (p.isCancel(install)) {\n await dismissPrompt('findSkillsPrompt');\n return;\n }\n\n if (install) {\n // Install find-skills to the same agents the user selected, excluding replit\n await dismissPrompt('findSkillsPrompt');\n\n // Filter out replit from target agents\n const findSkillsAgents = targetAgents?.filter((a) => a !== 'replit');\n\n // Skip if no valid agents remain after filtering\n if (!findSkillsAgents || findSkillsAgents.length === 0) {\n return;\n }\n\n console.log();\n p.log.step('Installing find-skills skill...');\n\n try {\n // Call runAdd directly\n await runAdd(['vercel-labs/skills'], {\n skill: ['find-skills'],\n global: true,\n yes: true,\n agent: findSkillsAgents,\n });\n } catch {\n p.log.warn('Failed to install find-skills. You can try again with:');\n p.log.message(pc.dim(' npx skills add vercel-labs/skills@find-skills -g -y --all'));\n }\n } else {\n // User declined - dismiss the prompt\n await dismissPrompt('findSkillsPrompt');\n p.log.message(\n pc.dim('You can install it later with: npx skills add vercel-labs/skills@find-skills')\n );\n }\n } catch {\n // Don't fail the main installation if prompt fails\n }\n}\n\n// Parse command line options from args array\nexport function parseAddOptions(args: string[]): { source: string[]; options: AddOptions } {\n const options: AddOptions = {};\n const source: string[] = [];\n\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n\n if (arg === '-g' || arg === '--global') {\n options.global = true;\n } else if (arg === '-y' || arg === '--yes') {\n options.yes = true;\n } else if (arg === '-l' || arg === '--list') {\n options.list = true;\n } else if (arg === '--all') {\n options.all = true;\n } else if (arg === '-a' || arg === '--agent') {\n options.agent = options.agent || [];\n i++;\n let nextArg = args[i];\n while (i < args.length && nextArg && !nextArg.startsWith('-')) {\n options.agent.push(nextArg);\n i++;\n nextArg = args[i];\n }\n i--; // Back up one since the loop will increment\n } else if (arg === '-s' || arg === '--skill') {\n options.skill = options.skill || [];\n i++;\n let nextArg = args[i];\n while (i < args.length && nextArg && !nextArg.startsWith('-')) {\n options.skill.push(nextArg);\n i++;\n nextArg = args[i];\n }\n i--; // Back up one since the loop will increment\n } else if (arg === '--full-depth') {\n options.fullDepth = true;\n } else if (arg === '--copy') {\n options.copy = true;\n } else if (arg && !arg.startsWith('-')) {\n source.push(arg);\n }\n }\n\n return { source, options };\n}\n","import * as readline from 'readline';\nimport { runAdd, parseAddOptions } from './add.ts';\nimport { track } from './telemetry.ts';\nimport { isRepoPrivate } from './source-parser.ts';\n\nconst RESET = '\\x1b[0m';\nconst BOLD = '\\x1b[1m';\nconst DIM = '\\x1b[38;5;102m';\nconst TEXT = '\\x1b[38;5;145m';\nconst CYAN = '\\x1b[36m';\nconst MAGENTA = '\\x1b[35m';\nconst YELLOW = '\\x1b[33m';\n\n// API endpoint for skills search\nconst SEARCH_API_BASE = process.env.SKILLS_API_URL || 'https://skills.sh';\n\nfunction formatInstalls(count: number): string {\n if (!count || count <= 0) return '';\n if (count >= 1_000_000) return `${(count / 1_000_000).toFixed(1).replace(/\\.0$/, '')}M installs`;\n if (count >= 1_000) return `${(count / 1_000).toFixed(1).replace(/\\.0$/, '')}K installs`;\n return `${count} install${count === 1 ? '' : 's'}`;\n}\n\nexport interface SearchSkill {\n name: string;\n slug: string;\n source: string;\n installs: number;\n}\n\n// Search via API\nexport async function searchSkillsAPI(query: string): Promise<SearchSkill[]> {\n try {\n const url = `${SEARCH_API_BASE}/api/search?q=${encodeURIComponent(query)}&limit=10`;\n const res = await fetch(url);\n\n if (!res.ok) return [];\n\n const data = (await res.json()) as {\n skills: Array<{\n id: string;\n name: string;\n installs: number;\n source: string;\n }>;\n };\n\n return data.skills.map((skill) => ({\n name: skill.name,\n slug: skill.id,\n source: skill.source || '',\n installs: skill.installs,\n }));\n } catch {\n return [];\n }\n}\n\n// ANSI escape codes for terminal control\nconst HIDE_CURSOR = '\\x1b[?25l';\nconst SHOW_CURSOR = '\\x1b[?25h';\nconst CLEAR_DOWN = '\\x1b[J';\nconst MOVE_UP = (n: number) => `\\x1b[${n}A`;\nconst MOVE_TO_COL = (n: number) => `\\x1b[${n}G`;\n\n// Custom fzf-style search prompt using raw readline\nasync function runSearchPrompt(initialQuery = ''): Promise<SearchSkill | null> {\n let results: SearchSkill[] = [];\n let selectedIndex = 0;\n let query = initialQuery;\n let loading = false;\n let debounceTimer: ReturnType<typeof setTimeout> | null = null;\n let lastRenderedLines = 0;\n\n // Enable raw mode for keypress events\n if (process.stdin.isTTY) {\n process.stdin.setRawMode(true);\n }\n\n // Setup readline for keypress events but don't let it echo\n readline.emitKeypressEvents(process.stdin);\n\n // Resume stdin to start receiving events\n process.stdin.resume();\n\n // Hide cursor during selection\n process.stdout.write(HIDE_CURSOR);\n\n function render(): void {\n // Move cursor up to overwrite previous render\n if (lastRenderedLines > 0) {\n process.stdout.write(MOVE_UP(lastRenderedLines) + MOVE_TO_COL(1));\n }\n\n // Clear from cursor to end of screen (removes ghost trails)\n process.stdout.write(CLEAR_DOWN);\n\n const lines: string[] = [];\n\n // Search input line with cursor\n const cursor = `${BOLD}_${RESET}`;\n lines.push(`${TEXT}Search skills:${RESET} ${query}${cursor}`);\n lines.push('');\n\n // Results - keep showing existing results while loading new ones\n if (!query || query.length < 2) {\n lines.push(`${DIM}Start typing to search (min 2 chars)${RESET}`);\n } else if (results.length === 0 && loading) {\n lines.push(`${DIM}Searching...${RESET}`);\n } else if (results.length === 0) {\n lines.push(`${DIM}No skills found${RESET}`);\n } else {\n const maxVisible = 8;\n const visible = results.slice(0, maxVisible);\n\n for (let i = 0; i < visible.length; i++) {\n const skill = visible[i]!;\n const isSelected = i === selectedIndex;\n const arrow = isSelected ? `${BOLD}>${RESET}` : ' ';\n const name = isSelected ? `${BOLD}${skill.name}${RESET}` : `${TEXT}${skill.name}${RESET}`;\n const source = skill.source ? ` ${DIM}${skill.source}${RESET}` : '';\n const installs = formatInstalls(skill.installs);\n const installsBadge = installs ? ` ${CYAN}${installs}${RESET}` : '';\n const loadingIndicator = loading && i === 0 ? ` ${DIM}...${RESET}` : '';\n\n lines.push(` ${arrow} ${name}${source}${installsBadge}${loadingIndicator}`);\n }\n }\n\n lines.push('');\n lines.push(`${DIM}up/down navigate | enter select | esc cancel${RESET}`);\n\n // Write each line\n for (const line of lines) {\n process.stdout.write(line + '\\n');\n }\n\n lastRenderedLines = lines.length;\n }\n\n function triggerSearch(q: string): void {\n // Always clear any pending debounce timer\n if (debounceTimer) {\n clearTimeout(debounceTimer);\n debounceTimer = null;\n }\n\n // Always reset loading state when starting a new search\n loading = false;\n\n if (!q || q.length < 2) {\n results = [];\n selectedIndex = 0;\n render();\n return;\n }\n\n // Use API search for all queries (debounced)\n loading = true;\n render();\n\n // Adaptive debounce: shorter queries = longer wait (user still typing)\n // 2 chars: 250ms, 3 chars: 200ms, 4 chars: 150ms, 5+ chars: 150ms\n const debounceMs = Math.max(150, 350 - q.length * 50);\n\n debounceTimer = setTimeout(async () => {\n try {\n results = await searchSkillsAPI(q);\n selectedIndex = 0;\n } catch {\n results = [];\n } finally {\n loading = false;\n debounceTimer = null;\n render();\n }\n }, debounceMs);\n }\n\n // Trigger initial search if there's a query, then render\n if (initialQuery) {\n triggerSearch(initialQuery);\n }\n render();\n\n return new Promise((resolve) => {\n function cleanup(): void {\n process.stdin.removeListener('keypress', handleKeypress);\n if (process.stdin.isTTY) {\n process.stdin.setRawMode(false);\n }\n process.stdout.write(SHOW_CURSOR);\n // Pause stdin to fully release it for child processes\n process.stdin.pause();\n }\n\n function handleKeypress(_ch: string | undefined, key: readline.Key): void {\n if (!key) return;\n\n if (key.name === 'escape' || (key.ctrl && key.name === 'c')) {\n // Cancel\n cleanup();\n resolve(null);\n return;\n }\n\n if (key.name === 'return') {\n // Submit\n cleanup();\n resolve(results[selectedIndex] || null);\n return;\n }\n\n if (key.name === 'up') {\n selectedIndex = Math.max(0, selectedIndex - 1);\n render();\n return;\n }\n\n if (key.name === 'down') {\n selectedIndex = Math.min(Math.max(0, results.length - 1), selectedIndex + 1);\n render();\n return;\n }\n\n if (key.name === 'backspace') {\n if (query.length > 0) {\n query = query.slice(0, -1);\n triggerSearch(query);\n }\n return;\n }\n\n // Regular character input\n if (key.sequence && !key.ctrl && !key.meta && key.sequence.length === 1) {\n const char = key.sequence;\n if (char >= ' ' && char <= '~') {\n query += char;\n triggerSearch(query);\n }\n }\n }\n\n process.stdin.on('keypress', handleKeypress);\n });\n}\n\n// Parse owner/repo from a package string (for the find command)\nfunction getOwnerRepoFromString(pkg: string): { owner: string; repo: string } | null {\n // Handle owner/repo or owner/repo@skill\n const atIndex = pkg.lastIndexOf('@');\n const repoPath = atIndex > 0 ? pkg.slice(0, atIndex) : pkg;\n const match = repoPath.match(/^([^/]+)\\/([^/]+)$/);\n if (match) {\n return { owner: match[1]!, repo: match[2]! };\n }\n return null;\n}\n\nasync function isRepoPublic(owner: string, repo: string): Promise<boolean> {\n const isPrivate = await isRepoPrivate(owner, repo);\n // Return true only if we know it's public (isPrivate === false)\n // Return false if private or unable to determine\n return isPrivate === false;\n}\n\nexport async function runFind(args: string[]): Promise<void> {\n const query = args.join(' ');\n const isNonInteractive = !process.stdin.isTTY;\n const agentTip = `${DIM}Tip: if running in a coding agent, follow these steps:${RESET}\n${DIM} 1) npx skills find [query]${RESET}\n${DIM} 2) npx skills add <owner/repo@skill>${RESET}`;\n\n // Non-interactive mode: just print results and exit\n if (query) {\n const results = await searchSkillsAPI(query);\n\n // Track telemetry for non-interactive search\n track({\n event: 'find',\n query,\n resultCount: String(results.length),\n });\n\n if (results.length === 0) {\n console.log(`${DIM}No skills found for \"${query}\"${RESET}`);\n return;\n }\n\n console.log(`${DIM}Install with${RESET} npx skills add <owner/repo@skill>`);\n console.log();\n\n for (const skill of results.slice(0, 6)) {\n const pkg = skill.source || skill.slug;\n const installs = formatInstalls(skill.installs);\n console.log(\n `${TEXT}${pkg}@${skill.name}${RESET}${installs ? ` ${CYAN}${installs}${RESET}` : ''}`\n );\n console.log(`${DIM}└ https://skills.sh/${skill.slug}${RESET}`);\n console.log();\n }\n return;\n }\n\n // Interactive mode - show tip only if running non-interactively (likely in a coding agent)\n if (isNonInteractive) {\n console.log(agentTip);\n console.log();\n }\n const selected = await runSearchPrompt();\n\n // Track telemetry for interactive search\n track({\n event: 'find',\n query: '',\n resultCount: selected ? '1' : '0',\n interactive: '1',\n });\n\n if (!selected) {\n console.log(`${DIM}Search cancelled${RESET}`);\n console.log();\n return;\n }\n\n // Use source (owner/repo) and skill name for installation\n const pkg = selected.source || selected.slug;\n const skillName = selected.name;\n\n console.log();\n console.log(`${TEXT}Installing ${BOLD}${skillName}${RESET} from ${DIM}${pkg}${RESET}...`);\n console.log();\n\n // Run add directly since we're in the same CLI\n const { source, options } = parseAddOptions([pkg, '--skill', skillName]);\n await runAdd(source, options);\n\n console.log();\n\n const info = getOwnerRepoFromString(pkg);\n if (info && (await isRepoPublic(info.owner, info.repo))) {\n console.log(\n `${DIM}View the skill at${RESET} ${TEXT}https://skills.sh/${selected.slug}${RESET}`\n );\n } else {\n console.log(`${DIM}Discover more skills at${RESET} ${TEXT}https://skills.sh${RESET}`);\n }\n\n console.log();\n}\n","import * as p from '@clack/prompts';\nimport pc from 'picocolors';\nimport { readdir, stat } from 'fs/promises';\nimport { join, sep } from 'path';\nimport { homedir } from 'os';\nimport { parseSkillMd } from './skills.ts';\nimport { installSkillForAgent, getCanonicalPath } from './installer.ts';\nimport {\n detectInstalledAgents,\n agents,\n getUniversalAgents,\n getNonUniversalAgents,\n} from './agents.ts';\nimport { searchMultiselect } from './prompts/search-multiselect.ts';\nimport { addSkillToLocalLock, computeSkillFolderHash, readLocalLock } from './local-lock.ts';\nimport type { Skill, AgentType } from './types.ts';\nimport { track } from './telemetry.ts';\n\nconst isCancelled = (value: unknown): value is symbol => typeof value === 'symbol';\n\nexport interface SyncOptions {\n agent?: string[];\n yes?: boolean;\n force?: boolean;\n}\n\n/**\n * Shortens a path for display: replaces homedir with ~ and cwd with .\n */\nfunction shortenPath(fullPath: string, cwd: string): string {\n const home = homedir();\n if (fullPath === home || fullPath.startsWith(home + sep)) {\n return '~' + fullPath.slice(home.length);\n }\n if (fullPath === cwd || fullPath.startsWith(cwd + sep)) {\n return '.' + fullPath.slice(cwd.length);\n }\n return fullPath;\n}\n\n/**\n * Crawl node_modules for SKILL.md files.\n * Searches both top-level packages and scoped packages (@org/pkg).\n * Returns discovered skills with their source package name.\n */\nasync function discoverNodeModuleSkills(\n cwd: string\n): Promise<Array<Skill & { packageName: string }>> {\n const nodeModulesDir = join(cwd, 'node_modules');\n const skills: Array<Skill & { packageName: string }> = [];\n\n let topNames: string[];\n try {\n topNames = await readdir(nodeModulesDir);\n } catch {\n return skills;\n }\n\n const processPackageDir = async (pkgDir: string, packageName: string) => {\n // Check for SKILL.md at package root\n const rootSkill = await parseSkillMd(join(pkgDir, 'SKILL.md'));\n if (rootSkill) {\n skills.push({ ...rootSkill, packageName });\n return;\n }\n\n // Check common skill locations within the package\n const searchDirs = [pkgDir, join(pkgDir, 'skills'), join(pkgDir, '.agents', 'skills')];\n\n for (const searchDir of searchDirs) {\n try {\n const entries = await readdir(searchDir);\n for (const name of entries) {\n const skillDir = join(searchDir, name);\n try {\n const s = await stat(skillDir);\n if (!s.isDirectory()) continue;\n } catch {\n continue;\n }\n const skill = await parseSkillMd(join(skillDir, 'SKILL.md'));\n if (skill) {\n skills.push({ ...skill, packageName });\n }\n }\n } catch {\n // Directory doesn't exist\n }\n }\n };\n\n await Promise.all(\n topNames.map(async (name) => {\n if (name.startsWith('.')) return;\n\n const fullPath = join(nodeModulesDir, name);\n try {\n const s = await stat(fullPath);\n if (!s.isDirectory()) return;\n } catch {\n return;\n }\n\n if (name.startsWith('@')) {\n // Scoped package: read @org/* entries\n try {\n const scopeNames = await readdir(fullPath);\n await Promise.all(\n scopeNames.map(async (scopedName) => {\n const scopedPath = join(fullPath, scopedName);\n try {\n const s = await stat(scopedPath);\n if (!s.isDirectory()) return;\n } catch {\n return;\n }\n await processPackageDir(scopedPath, `${name}/${scopedName}`);\n })\n );\n } catch {\n // Scope directory not readable\n }\n } else {\n await processPackageDir(fullPath, name);\n }\n })\n );\n\n return skills;\n}\n\nexport async function runSync(args: string[], options: SyncOptions = {}): Promise<void> {\n const cwd = process.cwd();\n\n console.log();\n p.intro(pc.bgCyan(pc.black(' skills experimental_sync ')));\n\n const spinner = p.spinner();\n\n // 1. Discover skills from node_modules\n spinner.start('Scanning node_modules for skills...');\n const discoveredSkills = await discoverNodeModuleSkills(cwd);\n\n if (discoveredSkills.length === 0) {\n spinner.stop(pc.yellow('No skills found'));\n p.outro(pc.dim('No SKILL.md files found in node_modules.'));\n return;\n }\n\n spinner.stop(\n `Found ${pc.green(String(discoveredSkills.length))} skill${discoveredSkills.length > 1 ? 's' : ''} in node_modules`\n );\n\n // Show discovered skills\n for (const skill of discoveredSkills) {\n p.log.info(`${pc.cyan(skill.name)} ${pc.dim(`from ${skill.packageName}`)}`);\n if (skill.description) {\n p.log.message(pc.dim(` ${skill.description}`));\n }\n }\n\n // 2. Check which skills are already up-to-date via local lock\n const localLock = await readLocalLock(cwd);\n const toInstall: Array<Skill & { packageName: string }> = [];\n const upToDate: string[] = [];\n\n if (options.force) {\n toInstall.push(...discoveredSkills);\n p.log.info(pc.dim('Force mode: reinstalling all skills'));\n } else {\n for (const skill of discoveredSkills) {\n const existingEntry = localLock.skills[skill.name];\n if (existingEntry) {\n // Compute current hash and compare\n const currentHash = await computeSkillFolderHash(skill.path);\n if (currentHash === existingEntry.computedHash) {\n upToDate.push(skill.name);\n continue;\n }\n }\n toInstall.push(skill);\n }\n\n if (upToDate.length > 0) {\n p.log.info(\n pc.dim(`${upToDate.length} skill${upToDate.length !== 1 ? 's' : ''} already up to date`)\n );\n }\n\n if (toInstall.length === 0) {\n console.log();\n p.outro(pc.green('All skills are up to date.'));\n return;\n }\n }\n\n p.log.info(`${toInstall.length} skill${toInstall.length !== 1 ? 's' : ''} to install/update`);\n\n // 3. Select agents\n let targetAgents: AgentType[];\n const validAgents = Object.keys(agents);\n const universalAgents = getUniversalAgents();\n\n if (options.agent?.includes('*')) {\n targetAgents = validAgents as AgentType[];\n p.log.info(`Installing to all ${targetAgents.length} agents`);\n } else if (options.agent && options.agent.length > 0) {\n const invalidAgents = options.agent.filter((a) => !validAgents.includes(a));\n if (invalidAgents.length > 0) {\n p.log.error(`Invalid agents: ${invalidAgents.join(', ')}`);\n p.log.info(`Valid agents: ${validAgents.join(', ')}`);\n process.exit(1);\n }\n targetAgents = options.agent as AgentType[];\n } else {\n spinner.start('Loading agents...');\n const installedAgents = await detectInstalledAgents();\n const totalAgents = Object.keys(agents).length;\n spinner.stop(`${totalAgents} agents`);\n\n if (installedAgents.length === 0) {\n if (options.yes) {\n targetAgents = universalAgents;\n p.log.info('Installing to universal agents');\n } else {\n const otherAgents = getNonUniversalAgents();\n\n const otherChoices = otherAgents.map((a) => ({\n value: a,\n label: agents[a].displayName,\n hint: agents[a].skillsDir,\n }));\n\n const selected = await searchMultiselect({\n message: 'Which agents do you want to install to?',\n items: otherChoices,\n initialSelected: [],\n lockedSection: {\n title: 'Universal (.agents/skills)',\n items: universalAgents.map((a) => ({\n value: a,\n label: agents[a].displayName,\n })),\n },\n });\n\n if (isCancelled(selected)) {\n p.cancel('Sync cancelled');\n process.exit(0);\n }\n\n targetAgents = selected as AgentType[];\n }\n } else if (installedAgents.length === 1 || options.yes) {\n // Ensure universal agents are included\n targetAgents = [...installedAgents];\n for (const ua of universalAgents) {\n if (!targetAgents.includes(ua)) {\n targetAgents.push(ua);\n }\n }\n } else {\n const otherAgents = getNonUniversalAgents().filter((a) => installedAgents.includes(a));\n\n const otherChoices = otherAgents.map((a) => ({\n value: a,\n label: agents[a].displayName,\n hint: agents[a].skillsDir,\n }));\n\n const selected = await searchMultiselect({\n message: 'Which agents do you want to install to?',\n items: otherChoices,\n initialSelected: installedAgents.filter((a) => !universalAgents.includes(a)),\n lockedSection: {\n title: 'Universal (.agents/skills)',\n items: universalAgents.map((a) => ({\n value: a,\n label: agents[a].displayName,\n })),\n },\n });\n\n if (isCancelled(selected)) {\n p.cancel('Sync cancelled');\n process.exit(0);\n }\n\n targetAgents = selected as AgentType[];\n }\n }\n\n // 4. Build summary\n const summaryLines: string[] = [];\n for (const skill of toInstall) {\n const canonicalPath = getCanonicalPath(skill.name, { global: false });\n const shortCanonical = shortenPath(canonicalPath, cwd);\n summaryLines.push(`${pc.cyan(skill.name)} ${pc.dim(`← ${skill.packageName}`)}`);\n summaryLines.push(` ${pc.dim(shortCanonical)}`);\n }\n\n console.log();\n p.note(summaryLines.join('\\n'), 'Sync Summary');\n\n if (!options.yes) {\n const confirmed = await p.confirm({ message: 'Proceed with sync?' });\n\n if (p.isCancel(confirmed) || !confirmed) {\n p.cancel('Sync cancelled');\n process.exit(0);\n }\n }\n\n // 5. Install skills (always project-scoped, always symlink)\n spinner.start('Syncing skills...');\n\n const results: Array<{\n skill: string;\n packageName: string;\n agent: string;\n success: boolean;\n path: string;\n canonicalPath?: string;\n error?: string;\n }> = [];\n\n for (const skill of toInstall) {\n for (const agent of targetAgents) {\n const result = await installSkillForAgent(skill, agent, {\n global: false,\n cwd,\n mode: 'symlink',\n });\n results.push({\n skill: skill.name,\n packageName: skill.packageName,\n agent: agents[agent].displayName,\n success: result.success,\n path: result.path,\n canonicalPath: result.canonicalPath,\n error: result.error,\n });\n }\n }\n\n spinner.stop('Sync complete');\n\n // 6. Update local lock file\n const successful = results.filter((r) => r.success);\n const failed = results.filter((r) => !r.success);\n const successfulSkillNames = new Set(successful.map((r) => r.skill));\n\n for (const skill of toInstall) {\n if (successfulSkillNames.has(skill.name)) {\n try {\n const computedHash = await computeSkillFolderHash(skill.path);\n await addSkillToLocalLock(\n skill.name,\n {\n source: skill.packageName,\n sourceType: 'node_modules',\n computedHash,\n },\n cwd\n );\n } catch {\n // Don't fail sync if lock file update fails\n }\n }\n }\n\n // 7. Display results\n console.log();\n\n if (successful.length > 0) {\n const bySkill = new Map<string, typeof results>();\n for (const r of successful) {\n const skillResults = bySkill.get(r.skill) || [];\n skillResults.push(r);\n bySkill.set(r.skill, skillResults);\n }\n\n const resultLines: string[] = [];\n for (const [skillName, skillResults] of bySkill) {\n const firstResult = skillResults[0]!;\n const pkg = toInstall.find((s) => s.name === skillName)?.packageName;\n if (firstResult.canonicalPath) {\n const shortPath = shortenPath(firstResult.canonicalPath, cwd);\n resultLines.push(`${pc.green('✓')} ${skillName} ${pc.dim(`← ${pkg}`)}`);\n resultLines.push(` ${pc.dim(shortPath)}`);\n } else {\n resultLines.push(`${pc.green('✓')} ${skillName} ${pc.dim(`← ${pkg}`)}`);\n }\n }\n\n const skillCount = bySkill.size;\n const title = pc.green(`Synced ${skillCount} skill${skillCount !== 1 ? 's' : ''}`);\n p.note(resultLines.join('\\n'), title);\n }\n\n if (failed.length > 0) {\n console.log();\n p.log.error(pc.red(`Failed to install ${failed.length}`));\n for (const r of failed) {\n p.log.message(` ${pc.red('✗')} ${r.skill} → ${r.agent}: ${pc.dim(r.error)}`);\n }\n }\n\n // Track telemetry\n track({\n event: 'experimental_sync',\n skillCount: String(toInstall.length),\n successCount: String(successfulSkillNames.size),\n agents: targetAgents.join(','),\n });\n\n console.log();\n p.outro(\n pc.green('Done!') + pc.dim(' Review skills before use; they run with full agent permissions.')\n );\n}\n\nexport function parseSyncOptions(args: string[]): { options: SyncOptions } {\n const options: SyncOptions = {};\n\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n\n if (arg === '-y' || arg === '--yes') {\n options.yes = true;\n } else if (arg === '-f' || arg === '--force') {\n options.force = true;\n } else if (arg === '-a' || arg === '--agent') {\n options.agent = options.agent || [];\n i++;\n let nextArg = args[i];\n while (i < args.length && nextArg && !nextArg.startsWith('-')) {\n options.agent.push(nextArg);\n i++;\n nextArg = args[i];\n }\n i--;\n }\n }\n\n return { options };\n}\n","import * as p from '@clack/prompts';\nimport pc from 'picocolors';\nimport { readLocalLock } from './local-lock.ts';\nimport { runAdd } from './add.ts';\nimport { runSync, parseSyncOptions } from './sync.ts';\nimport { getUniversalAgents } from './agents.ts';\n\n/**\n * Install all skills from the local skills-lock.json.\n * Groups skills by source and calls `runAdd` for each group.\n *\n * Only installs to .agents/skills/ (universal agents) -- the canonical\n * project-level location. Does not install to agent-specific directories.\n *\n * node_modules skills are handled via experimental_sync.\n */\nexport async function runInstallFromLock(args: string[]): Promise<void> {\n const cwd = process.cwd();\n const lock = await readLocalLock(cwd);\n const skillEntries = Object.entries(lock.skills);\n\n if (skillEntries.length === 0) {\n p.log.warn('No project skills found in skills-lock.json');\n p.log.info(\n `Add project-level skills with ${pc.cyan('npx skills add <package>')} (without ${pc.cyan('-g')})`\n );\n return;\n }\n\n // Only install to .agents/skills/ (universal agents)\n const universalAgentNames = getUniversalAgents();\n\n // Separate node_modules skills from remote skills\n const nodeModuleSkills: string[] = [];\n const bySource = new Map<string, { sourceType: string; skills: string[] }>();\n\n for (const [skillName, entry] of skillEntries) {\n if (entry.sourceType === 'node_modules') {\n nodeModuleSkills.push(skillName);\n continue;\n }\n\n const existing = bySource.get(entry.source);\n if (existing) {\n existing.skills.push(skillName);\n } else {\n bySource.set(entry.source, {\n sourceType: entry.sourceType,\n skills: [skillName],\n });\n }\n }\n\n const remoteCount = skillEntries.length - nodeModuleSkills.length;\n if (remoteCount > 0) {\n p.log.info(\n `Restoring ${pc.cyan(String(remoteCount))} skill${remoteCount !== 1 ? 's' : ''} from skills-lock.json into ${pc.dim('.agents/skills/')}`\n );\n }\n\n // Install remote skills grouped by source\n for (const [source, { skills }] of bySource) {\n try {\n await runAdd([source], {\n skill: skills,\n agent: universalAgentNames,\n yes: true,\n });\n } catch (error) {\n p.log.error(\n `Failed to install from ${pc.cyan(source)}: ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n }\n }\n\n // Handle node_modules skills via sync\n if (nodeModuleSkills.length > 0) {\n p.log.info(\n `${pc.cyan(String(nodeModuleSkills.length))} skill${nodeModuleSkills.length !== 1 ? 's' : ''} from node_modules`\n );\n try {\n const { options: syncOptions } = parseSyncOptions(args);\n await runSync(args, { ...syncOptions, yes: true, agent: universalAgentNames });\n } catch (error) {\n p.log.error(\n `Failed to sync node_modules skills: ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n }\n }\n}\n","import { homedir } from 'os';\nimport type { AgentType } from './types.ts';\nimport { agents } from './agents.ts';\nimport { listInstalledSkills, type InstalledSkill } from './installer.ts';\nimport { getAllLockedSkills } from './skill-lock.ts';\n\nconst RESET = '\\x1b[0m';\nconst BOLD = '\\x1b[1m';\nconst DIM = '\\x1b[38;5;102m';\nconst TEXT = '\\x1b[38;5;145m';\nconst CYAN = '\\x1b[36m';\nconst YELLOW = '\\x1b[33m';\n\ninterface ListOptions {\n global?: boolean;\n agent?: string[];\n}\n\n/**\n * Shortens a path for display: replaces homedir with ~ and cwd with .\n */\nfunction shortenPath(fullPath: string, cwd: string): string {\n const home = homedir();\n if (fullPath.startsWith(home)) {\n return fullPath.replace(home, '~');\n }\n if (fullPath.startsWith(cwd)) {\n return '.' + fullPath.slice(cwd.length);\n }\n return fullPath;\n}\n\n/**\n * Formats a list of items, truncating if too many\n */\nfunction formatList(items: string[], maxShow: number = 5): string {\n if (items.length <= maxShow) {\n return items.join(', ');\n }\n const shown = items.slice(0, maxShow);\n const remaining = items.length - maxShow;\n return `${shown.join(', ')} +${remaining} more`;\n}\n\nexport function parseListOptions(args: string[]): ListOptions {\n const options: ListOptions = {};\n\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n if (arg === '-g' || arg === '--global') {\n options.global = true;\n } else if (arg === '-a' || arg === '--agent') {\n options.agent = options.agent || [];\n // Collect all following arguments until next flag\n while (i + 1 < args.length && !args[i + 1]!.startsWith('-')) {\n options.agent.push(args[++i]!);\n }\n }\n }\n\n return options;\n}\n\nexport async function runList(args: string[]): Promise<void> {\n const options = parseListOptions(args);\n\n // Default to project only (local), use -g for global\n const scope = options.global === true ? true : false;\n\n // Validate agent filter if provided\n let agentFilter: AgentType[] | undefined;\n if (options.agent && options.agent.length > 0) {\n const validAgents = Object.keys(agents);\n const invalidAgents = options.agent.filter((a) => !validAgents.includes(a));\n\n if (invalidAgents.length > 0) {\n console.log(`${YELLOW}Invalid agents: ${invalidAgents.join(', ')}${RESET}`);\n console.log(`${DIM}Valid agents: ${validAgents.join(', ')}${RESET}`);\n process.exit(1);\n }\n\n agentFilter = options.agent as AgentType[];\n }\n\n const installedSkills = await listInstalledSkills({\n global: scope,\n agentFilter,\n });\n\n // Fetch lock entries to get plugin grouping info\n const lockedSkills = await getAllLockedSkills();\n\n const cwd = process.cwd();\n const scopeLabel = scope ? 'Global' : 'Project';\n\n if (installedSkills.length === 0) {\n console.log(`${DIM}No ${scopeLabel.toLowerCase()} skills found.${RESET}`);\n if (scope) {\n console.log(`${DIM}Try listing project skills without -g${RESET}`);\n } else {\n console.log(`${DIM}Try listing global skills with -g${RESET}`);\n }\n return;\n }\n\n function printSkill(skill: InstalledSkill, indent: boolean = false): void {\n const prefix = indent ? ' ' : '';\n const shortPath = shortenPath(skill.canonicalPath, cwd);\n const agentNames = skill.agents.map((a) => agents[a].displayName);\n const agentInfo =\n skill.agents.length > 0 ? formatList(agentNames) : `${YELLOW}not linked${RESET}`;\n console.log(`${prefix}${CYAN}${skill.name}${RESET} ${DIM}${shortPath}${RESET}`);\n console.log(`${prefix} ${DIM}Agents:${RESET} ${agentInfo}`);\n }\n\n console.log(`${BOLD}${scopeLabel} Skills${RESET}`);\n console.log();\n\n // Group skills by plugin\n const groupedSkills: Record<string, InstalledSkill[]> = {};\n const ungroupedSkills: InstalledSkill[] = [];\n\n for (const skill of installedSkills) {\n const lockEntry = lockedSkills[skill.name];\n if (lockEntry?.pluginName) {\n const group = lockEntry.pluginName;\n if (!groupedSkills[group]) {\n groupedSkills[group] = [];\n }\n groupedSkills[group].push(skill);\n } else {\n ungroupedSkills.push(skill);\n }\n }\n\n const hasGroups = Object.keys(groupedSkills).length > 0;\n\n if (hasGroups) {\n // Print groups sorted alphabetically\n const sortedGroups = Object.keys(groupedSkills).sort();\n for (const group of sortedGroups) {\n // Convert kebab-case to Title Case for display header\n const title = group\n .split('-')\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1))\n .join(' ');\n\n console.log(`${BOLD}${title}${RESET}`);\n const skills = groupedSkills[group];\n if (skills) {\n for (const skill of skills) {\n printSkill(skill, true);\n }\n }\n console.log();\n }\n\n // Print ungrouped skills if any exist\n if (ungroupedSkills.length > 0) {\n console.log(`${BOLD}General${RESET}`);\n for (const skill of ungroupedSkills) {\n printSkill(skill, true);\n }\n console.log();\n }\n } else {\n // No groups, print flat list as before\n for (const skill of installedSkills) {\n printSkill(skill);\n }\n console.log();\n }\n}\n","import * as p from '@clack/prompts';\nimport pc from 'picocolors';\nimport { readdir, rm, lstat } from 'fs/promises';\nimport { join } from 'path';\nimport { agents, detectInstalledAgents } from './agents.ts';\nimport { track } from './telemetry.ts';\nimport { removeSkillFromLock, getSkillFromLock } from './skill-lock.ts';\nimport type { AgentType } from './types.ts';\nimport {\n getInstallPath,\n getCanonicalPath,\n getCanonicalSkillsDir,\n sanitizeName,\n} from './installer.ts';\n\nexport interface RemoveOptions {\n global?: boolean;\n agent?: string[];\n yes?: boolean;\n all?: boolean;\n}\n\nexport async function removeCommand(skillNames: string[], options: RemoveOptions) {\n const isGlobal = options.global ?? false;\n const cwd = process.cwd();\n\n const spinner = p.spinner();\n\n spinner.start('Scanning for installed skills...');\n const skillNamesSet = new Set<string>();\n\n const scanDir = async (dir: string) => {\n try {\n const entries = await readdir(dir, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.isDirectory()) {\n skillNamesSet.add(entry.name);\n }\n }\n } catch (err) {\n if (err instanceof Error && (err as { code?: string }).code !== 'ENOENT') {\n p.log.warn(`Could not scan directory ${dir}: ${err.message}`);\n }\n }\n };\n\n if (isGlobal) {\n await scanDir(getCanonicalSkillsDir(true, cwd));\n for (const agent of Object.values(agents)) {\n if (agent.globalSkillsDir !== undefined) {\n await scanDir(agent.globalSkillsDir);\n }\n }\n } else {\n await scanDir(getCanonicalSkillsDir(false, cwd));\n for (const agent of Object.values(agents)) {\n await scanDir(join(cwd, agent.skillsDir));\n }\n }\n\n const installedSkills = Array.from(skillNamesSet).sort();\n spinner.stop(`Found ${installedSkills.length} unique installed skill(s)`);\n\n if (installedSkills.length === 0) {\n p.outro(pc.yellow('No skills found to remove.'));\n return;\n }\n\n // Validate agent options BEFORE prompting for skill selection\n if (options.agent && options.agent.length > 0) {\n const validAgents = Object.keys(agents);\n const invalidAgents = options.agent.filter((a) => !validAgents.includes(a));\n\n if (invalidAgents.length > 0) {\n p.log.error(`Invalid agents: ${invalidAgents.join(', ')}`);\n p.log.info(`Valid agents: ${validAgents.join(', ')}`);\n process.exit(1);\n }\n }\n\n let selectedSkills: string[] = [];\n\n if (options.all) {\n selectedSkills = installedSkills;\n } else if (skillNames.length > 0) {\n selectedSkills = installedSkills.filter((s) =>\n skillNames.some((name) => name.toLowerCase() === s.toLowerCase())\n );\n\n if (selectedSkills.length === 0) {\n p.log.error(`No matching skills found for: ${skillNames.join(', ')}`);\n return;\n }\n } else {\n const choices = installedSkills.map((s) => ({\n value: s,\n label: s,\n }));\n\n const selected = await p.multiselect({\n message: `Select skills to remove ${pc.dim('(space to toggle)')}`,\n options: choices,\n required: true,\n });\n\n if (p.isCancel(selected)) {\n p.cancel('Removal cancelled');\n process.exit(0);\n }\n\n selectedSkills = selected as string[];\n }\n\n let targetAgents: AgentType[];\n if (options.agent && options.agent.length > 0) {\n targetAgents = options.agent as AgentType[];\n } else {\n // When removing, we should target all known agents to ensure\n // ghost symlinks are cleaned up, even if the agent is not detected.\n targetAgents = Object.keys(agents) as AgentType[];\n spinner.stop(`Targeting ${targetAgents.length} potential agent(s)`);\n }\n\n if (!options.yes) {\n console.log();\n p.log.info('Skills to remove:');\n for (const skill of selectedSkills) {\n p.log.message(` ${pc.red('•')} ${skill}`);\n }\n console.log();\n\n const confirmed = await p.confirm({\n message: `Are you sure you want to uninstall ${selectedSkills.length} skill(s)?`,\n });\n\n if (p.isCancel(confirmed) || !confirmed) {\n p.cancel('Removal cancelled');\n process.exit(0);\n }\n }\n\n spinner.start('Removing skills...');\n\n const results: {\n skill: string;\n success: boolean;\n source?: string;\n sourceType?: string;\n error?: string;\n }[] = [];\n\n for (const skillName of selectedSkills) {\n try {\n const canonicalPath = getCanonicalPath(skillName, { global: isGlobal, cwd });\n\n for (const agentKey of targetAgents) {\n const agent = agents[agentKey];\n const skillPath = getInstallPath(skillName, agentKey, { global: isGlobal, cwd });\n\n // Determine potential paths to cleanup. For universal agents, getInstallPath\n // now returns the canonical path, so we also need to check their 'native'\n // directory to clean up any legacy symlinks.\n const pathsToCleanup = new Set([skillPath]);\n const sanitizedName = sanitizeName(skillName);\n if (isGlobal && agent.globalSkillsDir) {\n pathsToCleanup.add(join(agent.globalSkillsDir, sanitizedName));\n } else {\n pathsToCleanup.add(join(cwd, agent.skillsDir, sanitizedName));\n }\n\n for (const pathToCleanup of pathsToCleanup) {\n // Skip if this is the canonical path - we'll handle that after checking all agents\n if (pathToCleanup === canonicalPath) {\n continue;\n }\n\n try {\n const stats = await lstat(pathToCleanup).catch(() => null);\n if (stats) {\n await rm(pathToCleanup, { recursive: true, force: true });\n }\n } catch (err) {\n p.log.warn(\n `Could not remove skill from ${agent.displayName}: ${\n err instanceof Error ? err.message : String(err)\n }`\n );\n }\n }\n }\n\n // Only remove the canonical path if no other installed agents are using it.\n // This prevents breaking other agents when uninstalling from a specific agent (#287).\n const installedAgents = await detectInstalledAgents();\n const remainingAgents = installedAgents.filter((a) => !targetAgents.includes(a));\n\n let isStillUsed = false;\n for (const agentKey of remainingAgents) {\n const path = getInstallPath(skillName, agentKey, { global: isGlobal, cwd });\n const exists = await lstat(path).catch(() => null);\n if (exists) {\n isStillUsed = true;\n break;\n }\n }\n\n if (!isStillUsed) {\n await rm(canonicalPath, { recursive: true, force: true });\n }\n\n const lockEntry = isGlobal ? await getSkillFromLock(skillName) : null;\n const effectiveSource = lockEntry?.source || 'local';\n const effectiveSourceType = lockEntry?.sourceType || 'local';\n\n if (isGlobal) {\n await removeSkillFromLock(skillName);\n }\n\n results.push({\n skill: skillName,\n success: true,\n source: effectiveSource,\n sourceType: effectiveSourceType,\n });\n } catch (err) {\n results.push({\n skill: skillName,\n success: false,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n }\n\n spinner.stop('Removal process complete');\n\n const successful = results.filter((r) => r.success);\n const failed = results.filter((r) => !r.success);\n\n // Track removal (grouped by source)\n if (successful.length > 0) {\n const bySource = new Map<string, { skills: string[]; sourceType?: string }>();\n\n for (const r of successful) {\n const source = r.source || 'local';\n const existing = bySource.get(source) || { skills: [] };\n existing.skills.push(r.skill);\n existing.sourceType = r.sourceType;\n bySource.set(source, existing);\n }\n\n for (const [source, data] of bySource) {\n track({\n event: 'remove',\n source,\n skills: data.skills.join(','),\n agents: targetAgents.join(','),\n ...(isGlobal && { global: '1' }),\n sourceType: data.sourceType,\n });\n }\n }\n\n if (successful.length > 0) {\n p.log.success(pc.green(`Successfully removed ${successful.length} skill(s)`));\n }\n\n if (failed.length > 0) {\n p.log.error(pc.red(`Failed to remove ${failed.length} skill(s)`));\n for (const r of failed) {\n p.log.message(` ${pc.red('✗')} ${r.skill}: ${r.error}`);\n }\n }\n\n console.log();\n p.outro(pc.green('Done!'));\n}\n\n/**\n * Parse command line options for the remove command.\n * Separates skill names from options flags.\n */\nexport function parseRemoveOptions(args: string[]): { skills: string[]; options: RemoveOptions } {\n const options: RemoveOptions = {};\n const skills: string[] = [];\n\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n\n if (arg === '-g' || arg === '--global') {\n options.global = true;\n } else if (arg === '-y' || arg === '--yes') {\n options.yes = true;\n } else if (arg === '--all') {\n options.all = true;\n } else if (arg === '-a' || arg === '--agent') {\n options.agent = options.agent || [];\n i++;\n let nextArg = args[i];\n while (i < args.length && nextArg && !nextArg.startsWith('-')) {\n options.agent.push(nextArg);\n i++;\n nextArg = args[i];\n }\n i--; // Back up one since the loop will increment\n } else if (arg && !arg.startsWith('-')) {\n skills.push(arg);\n }\n }\n\n return { skills, options };\n}\n","import { promises as fs } from 'fs';\nimport { join, dirname } from 'path';\nimport { homedir } from 'os';\nimport type { AgentType } from './types.ts';\nimport type {\n McpConfig,\n McpServerConfig,\n SkillsMcpAgentConfig,\n SkillsMcpServerConfig,\n} from '@codemcp/skills-core';\nimport {\n McpConfigAdapterRegistry,\n ConfigGeneratorRegistry,\n GitHubCopilotGenerator,\n KiroGenerator,\n OpenCodeMcpGenerator,\n OpenCodeAgentGenerator,\n VsCodeGenerator,\n} from '@codemcp/skills-core';\n\n/**\n * Type mapping from simplified agent names to MCP client types\n */\nconst AGENT_TO_MCP_CLIENT: Record<string, string> = {\n 'claude-code': 'claude-desktop',\n claude: 'claude-desktop',\n cline: 'cline',\n cursor: 'cursor',\n 'kiro-cli': 'kiro',\n kiro: 'kiro',\n junie: 'junie',\n opencode: 'opencode',\n zed: 'zed',\n continue: 'continue',\n 'github-copilot': 'github-copilot',\n 'mistral-vibe': 'mistral-vibe',\n windsurf: 'windsurf',\n codex: 'codex',\n 'command-code': 'command-code',\n cortex: 'cortex',\n crush: 'crush',\n droid: 'droid',\n 'gemini-cli': 'gemini-cli',\n goose: 'goose',\n 'iflow-cli': 'iflow-cli',\n kilo: 'kilo',\n 'kimi-cli': 'kimi-cli',\n kode: 'kode',\n mcpjam: 'mcpjam',\n mux: 'mux',\n neovate: 'neovate',\n openhands: 'openhands',\n pi: 'pi',\n qoder: 'qoder',\n 'qwen-code': 'qwen-code',\n replit: 'replit',\n roo: 'roo',\n trae: 'trae',\n 'trae-cn': 'trae-cn',\n zencoder: 'zencoder',\n pochi: 'pochi',\n adal: 'adal',\n universal: 'universal',\n amp: 'amp',\n antigravity: 'antigravity',\n augment: 'augment',\n openclaw: 'openclaw',\n codebuddy: 'codebuddy',\n};\n\n/**\n * Get the MCP configuration file path for an agent\n * @param agentType The agent type\n * @param cwd Current working directory (or home directory for global)\n * @param scope 'local' for project, 'global' for home directory\n * @returns The full path to the agent's MCP config file\n */\nexport function getAgentConfigPath(\n agentType: AgentType | string,\n cwd: string,\n scope: 'local' | 'global' = 'local'\n): string {\n const mappedType = AGENT_TO_MCP_CLIENT[agentType] || agentType;\n // Note: cwd already contains the home directory if scope='global'\n\n switch (mappedType) {\n case 'claude-desktop':\n // Claude Desktop: store MCP config in project or home .claude/mcp.json\n return join(cwd, '.claude', 'mcp.json');\n case 'cline':\n // Cline: store in .cline/mcp.json\n return join(cwd, '.cline', 'mcp.json');\n case 'cursor':\n return join(cwd, '.cursor', 'mcp.json');\n case 'kiro':\n // Kiro: local .kiro/mcp.json | global ~/.kiro/agents/default.json\n if (scope === 'global') {\n return join(cwd, '.kiro', 'agents', 'default.json');\n }\n return join(cwd, '.kiro', 'mcp.json');\n case 'github-copilot':\n // GitHub Copilot runs in VS Code; VS Code reads .vscode/mcp.json (key: \"servers\")\n return join(cwd, '.vscode', 'mcp.json');\n case 'junie':\n // Junie: store in .junie/mcp.json\n return join(cwd, '.junie', 'mcp.json');\n case 'opencode':\n // OpenCode: local opencode.json | global ~/.config/opencode/opencode.json\n if (scope === 'global') {\n return join(cwd, '.config', 'opencode', 'opencode.json');\n }\n return join(cwd, 'opencode.json');\n case 'zed':\n return join(cwd, '.config', 'zed', 'settings.json');\n case 'continue':\n // Continue: store in .continue/config.json\n return join(cwd, '.continue', 'config.json');\n // For other agents, try to infer config path\n default:\n // Try to infer from agent name if possible\n const sanitized = mappedType.replace(/[^a-z0-9-]/gi, '_').toLowerCase();\n return join(cwd, `.${sanitized}`, 'mcp.json');\n }\n}\n\n/**\n * Read an agent's MCP configuration file.\n * Normalises agent-specific formats to the common McpConfig shape:\n * - VS Code (.vscode/mcp.json) uses \"servers\" → normalised to \"mcpServers\"\n * - OpenCode uses \"mcp\" → normalised to \"mcpServers\"\n * @param configPath Path to the config file\n * @returns The parsed config object, or empty config if file doesn't exist\n */\nexport async function readAgentConfig(configPath: string, agentType?: string): Promise<McpConfig> {\n try {\n const content = await fs.readFile(configPath, 'utf-8');\n const raw = JSON.parse(content) as Record<string, unknown>;\n\n // If agentType is provided, use the appropriate adapter to normalize format\n if (agentType) {\n const mappedType = AGENT_TO_MCP_CLIENT[agentType] || agentType;\n const adapter = McpConfigAdapterRegistry.getAdapter(mappedType as any);\n return adapter.toStandard(raw);\n }\n\n // No agentType provided - return raw config as-is\n // Caller is responsible for using the right adapter if needed\n return raw as unknown as McpConfig;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n return { mcpServers: {} };\n }\n throw error;\n }\n}\n\n/**\n * Write an agent's MCP configuration file\n * @param configPath Path to the config file\n * @param config The config object to write\n */\nexport async function writeAgentConfig(configPath: string, config: McpConfig): Promise<void> {\n const dir = dirname(configPath);\n await fs.mkdir(dir, { recursive: true });\n await fs.writeFile(configPath, JSON.stringify(config, null, 2) + '\\n');\n}\n\n/**\n * Configure MCP server for an agent\n * @param agentType The agent type (e.g., 'claude-code', 'cline', 'cursor')\n * @param cwd Current working directory (or home directory if configuring globally)\n * @param scope 'local' for project, 'global' for home directory\n */\nexport async function configureAgentMcp(\n agentType: AgentType | string,\n cwd: string,\n scope: 'local' | 'global' = 'local'\n): Promise<void> {\n // Validate agent type\n if (!agentType || typeof agentType !== 'string') {\n throw new Error(`Invalid agent type: ${agentType}`);\n }\n\n if (!AGENT_TO_MCP_CLIENT[agentType] && !isValidMcpClientType(agentType)) {\n throw new Error(`Unknown agent type: ${agentType}`);\n }\n\n // Get config path for this agent\n const configPath = getAgentConfigPath(agentType, cwd, scope);\n\n // Read existing config (use adapter to convert from agent-specific format if needed)\n let config = await readAgentConfig(configPath, agentType);\n\n // Ensure mcpServers exists\n if (!config.mcpServers) {\n config.mcpServers = {};\n }\n\n // Define the MCP server config\n const mcpServerConfig: McpServerConfig = {\n command: 'npx',\n args: ['-y', '@codemcp/skills-mcp'],\n };\n\n // Update or add agentskills server\n config.mcpServers.agentskills = mcpServerConfig;\n\n // Use the appropriate adapter for the agent type to convert to agent-specific format\n const mappedType = AGENT_TO_MCP_CLIENT[agentType] || agentType;\n const adapter = McpConfigAdapterRegistry.getAdapter(mappedType as any);\n\n // Read existing config for this agent (to preserve other settings)\n let existingAgentConfig: unknown;\n try {\n const existingContent = await fs.readFile(configPath, 'utf-8');\n existingAgentConfig = JSON.parse(existingContent);\n } catch {\n // File doesn't exist or isn't valid JSON, that's okay\n existingAgentConfig = undefined;\n }\n\n // Convert to agent-specific format using the adapter\n const agentSpecificConfig = adapter.toClient(config, existingAgentConfig);\n\n await writeAgentConfig(configPath, agentSpecificConfig as McpConfig);\n}\n\n/**\n * Check if a string is a valid MCP client type\n */\nfunction isValidMcpClientType(type: string): boolean {\n const validTypes = [\n 'claude-desktop',\n 'cline',\n 'cursor',\n 'kiro',\n 'junie',\n 'opencode',\n 'zed',\n 'continue',\n 'codium',\n ];\n return validTypes.includes(type);\n}\n\n/**\n * A shared registry instance so callers can check which agents are\n * generator-backed without re-instantiating.\n *\n * VsCodeGenerator handles github-copilot et al. (baseline .vscode/mcp.json).\n * GitHubCopilotGenerator is NOT registered here — it is invoked separately\n * and additively when agent-config mode is requested for github-copilot.\n */\nexport function buildConfigGeneratorRegistry(): ConfigGeneratorRegistry {\n const registry = new ConfigGeneratorRegistry();\n registry.register(new VsCodeGenerator());\n registry.register(new KiroGenerator());\n registry.register(new OpenCodeMcpGenerator());\n return registry;\n}\n\n/**\n * SAFETY: generators MUST target specific named files — never a directory.\n * We validate every resolved path before writing to enforce this contract.\n */\nasync function safeWrite(filePath: string, content: string): Promise<void> {\n try {\n const stat = await fs.stat(filePath);\n if (stat.isDirectory()) {\n throw new Error(\n `Generator returned a directory path instead of a file path: ${filePath}. ` +\n `Generators must write to a specific named file and must never clear or overwrite directories.`\n );\n }\n } catch (e) {\n if ((e as NodeJS.ErrnoException).code !== 'ENOENT') throw e;\n }\n const dir = dirname(filePath);\n await fs.mkdir(dir, { recursive: true });\n await fs.writeFile(filePath, content, 'utf-8');\n}\n\nasync function writeGeneratedConfig(generatedConfig: {\n files?: Array<{ path: string; content: string | Record<string, unknown> }>;\n filePath?: string | string[];\n content?: string | Record<string, unknown>;\n}): Promise<void> {\n if (generatedConfig.files) {\n for (const file of generatedConfig.files) {\n const content =\n typeof file.content === 'string' ? file.content : JSON.stringify(file.content, null, 2);\n await safeWrite(file.path, content);\n }\n } else {\n const content =\n typeof generatedConfig.content === 'string'\n ? generatedConfig.content\n : JSON.stringify(generatedConfig.content, null, 2);\n await safeWrite(generatedConfig.filePath as string, content);\n }\n}\n\n/**\n * Generate skills-mcp agent configuration using the ConfigGeneratorRegistry.\n *\n * For VS Code / GitHub Copilot the model is additive:\n * 1. `.vscode/mcp.json` is ALWAYS written (the baseline server registration)\n * 2. `.github/agents/skills-mcp.agent.md` is written ADDITIONALLY when\n * `includeAgentConfig` is true (default true for backward compatibility)\n *\n * @param agentType The agent type\n * @param cwd Current working directory (or home directory for global)\n * @param scope 'local' for project, 'global' for home directory\n * @param extraServers Additional MCP servers to include alongside agentskills\n * @param includeAgentConfig When true (default), also write the rich agent file\n * for agents that support one (GitHub Copilot: .github/agents/*.agent.md)\n */\nexport async function generateSkillsMcpAgent(\n agentType: AgentType | string,\n cwd: string,\n scope: 'local' | 'global' = 'local',\n extraServers?: Record<string, SkillsMcpServerConfig>,\n includeAgentConfig = true\n): Promise<void> {\n const registry = buildConfigGeneratorRegistry();\n const skillsDir = scope === 'global' ? homedir() : cwd;\n\n const baseConfig: SkillsMcpAgentConfig = {\n id: 'skills-mcp',\n description: 'Agent-skills MCP server with use_skill tool access',\n mcp_servers: {\n 'agent-skills': {\n type: 'stdio',\n command: 'npx',\n args: ['-y', '@codemcp/skills-mcp'],\n tools: ['*'],\n },\n ...extraServers,\n },\n tools: { use_skill: true },\n permissions: { use_skill: 'allow' },\n };\n\n const generatorOptions = {\n skillsDir,\n agentId: 'skills-mcp',\n scope,\n isGlobal: scope === 'global',\n includeAgentConfig,\n };\n\n const generator = registry.getGenerator(agentType as string);\n if (!generator) {\n throw new Error(\n `No config generator found for agent type: ${agentType}. Supported types: ${registry\n .getSupportedAgentTypes()\n .join(', ')}`\n );\n }\n\n // 1. Always write the baseline config (e.g. .vscode/mcp.json for github-copilot or opencode.json for opencode)\n await writeGeneratedConfig(await generator.generate(baseConfig, generatorOptions));\n\n // 2. For GitHub Copilot: additionally write the agent file when requested\n // (the VsCodeGenerator owns the baseline; GitHubCopilotGenerator owns the agent file)\n if (includeAgentConfig && generator instanceof VsCodeGenerator) {\n const agentFileGenerator = new GitHubCopilotGenerator();\n await writeGeneratedConfig(await agentFileGenerator.generate(baseConfig, generatorOptions));\n }\n\n // 3. For OpenCode: additionally write the agent file when requested\n // (the OpenCodeMcpGenerator owns the baseline opencode.json; OpenCodeAgentGenerator owns the agent file)\n if (includeAgentConfig && generator instanceof OpenCodeMcpGenerator) {\n const agentFileGenerator = new OpenCodeAgentGenerator();\n await writeGeneratedConfig(await agentFileGenerator.generate(baseConfig, generatorOptions));\n }\n}\n","/**\n * Handles MCP server dependencies declared in skill frontmatter via `requires-mcp-servers`.\n *\n * Called from `mcp setup` after configuring the agentskills server so that\n * every agent the user selects also receives the individual MCP servers that\n * the installed skills require.\n */\n\nimport { promises as fs } from 'fs';\nimport * as p from '@clack/prompts';\nimport pc from 'picocolors';\nimport type { AgentType, McpServerDependency } from './types.ts';\nimport type { SkillsMcpServerConfig } from '@codemcp/skills-core';\nimport { agents } from './agents.ts';\nimport {\n getAgentConfigPath,\n readAgentConfig,\n writeAgentConfig,\n generateSkillsMcpAgent,\n buildConfigGeneratorRegistry,\n} from './mcp-configurator.ts';\nimport { discoverSkills } from './skills.ts';\nimport { getCanonicalSkillsDir, getMCPCanonicalSkillsDir } from './installer.ts';\n\n// ── skill discovery ───────────────────────────────────────────────────────────\n\n/**\n * Load all installed skills for the given scope and return the unique set of\n * MCP server dependencies declared across them.\n */\nexport async function loadInstalledSkillMcpDeps(\n cwd: string,\n scope: 'local' | 'global'\n): Promise<McpServerDependency[]> {\n const isGlobal = scope === 'global';\n\n // Skills can live in the canonical .agents/skills dir or the MCP-server dir\n const searchDirs = [\n getCanonicalSkillsDir(isGlobal, cwd),\n getMCPCanonicalSkillsDir(isGlobal, cwd),\n ];\n\n const seen = new Map<string, McpServerDependency>();\n\n for (const dir of searchDirs) {\n try {\n const skills = await discoverSkills(dir, undefined, { fullDepth: true });\n for (const skill of skills) {\n for (const dep of skill.requiresMcpServers ?? []) {\n if (!seen.has(dep.name)) {\n seen.set(dep.name, dep);\n }\n }\n }\n } catch {\n // Directory may not exist — skip silently\n }\n }\n\n return [...seen.values()];\n}\n\n// ── parameter resolution ──────────────────────────────────────────────────────\n\n/** Replace `{{PARAM_NAME}}` placeholders with resolved values. */\nfunction substituteParam(value: string, params: Record<string, string>): string {\n return value.replace(\n /\\{\\{([A-Za-z0-9_-]+)\\}\\}/g,\n (_, key: string) => params[key] ?? `{{${key}}}`\n );\n}\n\nfunction applyParams(\n dep: McpServerDependency,\n params: Record<string, string>\n): { command: string; args?: string[]; env?: Record<string, string>; cwd?: string } {\n const result: { command: string; args?: string[]; env?: Record<string, string>; cwd?: string } = {\n command: dep.command,\n };\n if (dep.args?.length) result.args = dep.args.map((a) => substituteParam(a, params));\n if (dep.env && Object.keys(dep.env).length) {\n result.env = Object.fromEntries(\n Object.entries(dep.env).map(([k, v]) => [k, substituteParam(v, params)])\n );\n }\n if (dep.cwd) result.cwd = dep.cwd;\n return result;\n}\n\nasync function resolveParameters(dep: McpServerDependency): Promise<Record<string, string>> {\n const result: Record<string, string> = {};\n if (!dep.parameters) return result;\n\n for (const [paramName, spec] of Object.entries(dep.parameters)) {\n // Resolve env-var defaults: {{ENV:VAR_NAME}}\n let resolved = spec.default;\n if (resolved?.startsWith('{{ENV:')) {\n const m = resolved.match(/\\{\\{ENV:([A-Za-z0-9_]+)\\}\\}/);\n if (m) resolved = process.env[m[1]!] ?? undefined;\n }\n\n if (resolved !== undefined) {\n result[paramName] = resolved;\n continue;\n }\n\n if (!spec.required) continue; // optional with no default — leave placeholder\n\n // Required parameter without a default — prompt the user\n const answer = await p.text({\n message: `${pc.cyan(dep.name)} needs ${pc.bold(paramName)}: ${spec.description}`,\n });\n\n if (p.isCancel(answer)) {\n p.cancel('MCP server configuration cancelled');\n process.exit(0);\n }\n\n result[paramName] = answer as string;\n }\n\n return result;\n}\n\n// ── main export ───────────────────────────────────────────────────────────────\n\n/**\n * For each supplied agent, write any skill-required MCP servers that are not\n * yet present in that agent's config.\n *\n * The `configMode` parameter controls how generator-backed agents are handled:\n * - 'agent-config': deps are merged into the agent file via generateSkillsMcpAgent\n * - 'mcp-json': deps are written to the raw mcp.json path even for generator-backed agents\n *\n * For agents without a generator, mcp.json is always used regardless of configMode.\n *\n * In all cases the diff rule is: only check presence of the server key —\n * never modify an existing server's configuration.\n *\n * @param deps MCP server dependencies collected from installed skills.\n * @param agentTypes Agents that were just configured by `mcp setup`.\n * @param configCwd Base directory for agent config files.\n * @param scope 'local' or 'global'.\n * @param configMode Whether generator-backed agents use agent-config or mcp-json.\n */\nexport async function configureSkillMcpDepsForAgents(\n deps: McpServerDependency[],\n agentTypes: AgentType[],\n configCwd: string,\n scope: 'local' | 'global',\n configMode: 'agent-config' | 'mcp-json' = 'agent-config'\n): Promise<void> {\n if (deps.length === 0 || agentTypes.length === 0) return;\n\n // Resolve parameters once (shared across all agents)\n const resolvedConfigs = new Map<\n string,\n { command: string; args?: string[]; env?: Record<string, string>; cwd?: string }\n >();\n\n for (const dep of deps) {\n const params = await resolveParameters(dep);\n resolvedConfigs.set(dep.name, applyParams(dep, params));\n }\n\n // Determine routing per agent: generator-backed in agent-config mode → regenerate agent file\n const registry = buildConfigGeneratorRegistry();\n\n let anyConfigured = false;\n\n for (const agentType of agentTypes) {\n const useAgentConfig = configMode === 'agent-config' && registry.supports(agentType as string);\n\n if (useAgentConfig) {\n // ── Generator-backed agents (Kiro, GitHub Copilot, OpenCode) ──────────\n // The agent file already exists (written by generateSkillsMcpAgent).\n // We need to know which servers are already in it to diff correctly,\n // then regenerate with the full merged set.\n //\n // For simplicity we re-run generateSkillsMcpAgent with the extra servers\n // — the generator always writes the canonical set so idempotent runs are\n // safe. The existing agentskills entry is never duplicated because it is\n // hardcoded in generateSkillsMcpAgent's baseConfig.\n const missingServers: Record<string, SkillsMcpServerConfig> = {};\n for (const dep of deps) {\n const resolved = resolvedConfigs.get(dep.name)!;\n missingServers[dep.name] = {\n command: resolved.command,\n args: resolved.args,\n env: resolved.env,\n ...(resolved.cwd ? { cwd: resolved.cwd } : {}),\n };\n }\n\n try {\n await generateSkillsMcpAgent(agentType, configCwd, scope, missingServers);\n for (const dep of deps) {\n p.log.success(\n `${pc.green('✓')} Added ${pc.cyan(dep.name)} to ${pc.dim(agents[agentType as AgentType]?.displayName || agentType)}`\n );\n }\n anyConfigured = true;\n } catch {\n p.log.warn(\n pc.yellow(\n `Could not update agent config for ${agents[agentType as AgentType]?.displayName || agentType} — add skill MCP servers manually`\n )\n );\n }\n } else {\n // ── Raw mcp.json agents (Claude, Cursor, Cline, …) ───────────────────\n // Import here to avoid circular dependency\n const { McpConfigAdapterRegistry } = await import('@codemcp/skills-core');\n const configPath = getAgentConfigPath(agentType, configCwd, scope);\n const config = await readAgentConfig(configPath, agentType);\n if (!config.mcpServers) config.mcpServers = {};\n\n let anyServerAdded = false;\n for (const dep of deps) {\n if (config.mcpServers[dep.name]) continue; // already configured — don't touch\n\n config.mcpServers[dep.name] = resolvedConfigs.get(dep.name)! as {\n command: string;\n args?: string[];\n env?: Record<string, string>;\n };\n anyServerAdded = true;\n\n p.log.success(\n `${pc.green('✓')} Added ${pc.cyan(dep.name)} to ${pc.dim(agents[agentType as AgentType]?.displayName || agentType)}`\n );\n }\n\n if (anyServerAdded) {\n try {\n // Use the adapter to convert to agent-specific format if needed\n const { McpConfigAdapterRegistry } = await import('@codemcp/skills-core');\n const adapter = McpConfigAdapterRegistry.getAdapter(agentType as any);\n\n // Read existing config to preserve other settings\n let existingAgentConfig: unknown;\n try {\n const existingContent = await fs.readFile(configPath, 'utf-8');\n existingAgentConfig = JSON.parse(existingContent);\n } catch {\n // File doesn't exist or isn't valid JSON\n existingAgentConfig = undefined;\n }\n\n // Convert to agent-specific format\n const agentSpecificConfig = adapter.toClient(config, existingAgentConfig);\n\n // Write in agent-specific format\n await writeAgentConfig(configPath, agentSpecificConfig as any);\n anyConfigured = true;\n } catch (error) {\n p.log.warn(\n pc.yellow(\n `Could not update MCP config for ${agents[agentType as AgentType]?.displayName || agentType} — add skills manually`\n )\n );\n }\n }\n }\n }\n\n if (anyConfigured) {\n console.log();\n }\n}\n","import { homedir } from 'os';\nimport type { AgentType } from './types.ts';\nimport {\n generateSkillsMcpAgent,\n configureAgentMcp,\n buildConfigGeneratorRegistry,\n} from './mcp-configurator.ts';\nimport { agents, detectInstalledAgents } from './agents.ts';\nimport { multiselect, select, cancel } from '@clack/prompts';\nimport { loadInstalledSkillMcpDeps, configureSkillMcpDepsForAgents } from './mcp-skill-deps.ts';\n\n/**\n * Options parsed from mcp setup command\n */\nexport interface McpSetupOptions {\n mode: 'tui' | 'cli';\n agents: AgentType[];\n cwd?: string;\n scope?: 'local' | 'global'; // 'local' = project, 'global' = home directory\n configMode?: McpConfigMode; // explicit override; undefined = ask in TUI / auto in CLI\n}\n\n/**\n * The two config output modes the user can choose from.\n *\n * - 'agent-config' → uses ConfigGeneratorRegistry; produces a rich agent file\n * (.kiro/agents/skills-mcp.json, .github/agents/skills-mcp.agent.md, …)\n * that bundles MCP server registrations + usage instructions.\n * Only available for agents with a registered generator.\n *\n * - 'mcp-json' → plain {mcpServers:{…}} written to the agent's standard mcp.json path.\n * Works for every agent; no agent-specific instructions are written.\n */\nexport type McpConfigMode = 'agent-config' | 'mcp-json';\n\n/**\n * Parse mcp setup command arguments\n * Reuses the --agent flag pattern from add.ts\n * @param args Command arguments (e.g., ['setup', '--agent', 'claude-code', '--global'])\n * @returns Parsed options with mode, agents, and scope\n */\nexport function parseMcpOptions(args: string[]): McpSetupOptions {\n const agentList: AgentType[] = [];\n let scope: 'local' | 'global' = 'local';\n let configMode: McpConfigMode | undefined;\n\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n\n if (arg === '-a' || arg === '--agent') {\n i++;\n let nextArg = args[i];\n while (i < args.length && nextArg && !nextArg.startsWith('-')) {\n agentList.push(nextArg as AgentType);\n i++;\n nextArg = args[i];\n }\n i--;\n } else if (arg === '-g' || arg === '--global') {\n scope = 'global';\n } else if (arg === '--agent-config') {\n configMode = 'agent-config';\n } else if (arg === '--mcp-json') {\n configMode = 'mcp-json';\n }\n }\n\n const mode = agentList.length > 0 ? 'cli' : 'tui';\n\n return {\n mode,\n agents: agentList,\n scope,\n configMode,\n };\n}\n\n/**\n * Run the MCP setup command\n * @param options Options from parseMcpOptions\n * @param cwd Current working directory (defaults to process.cwd())\n */\nexport async function runMcpSetup(\n options: McpSetupOptions,\n cwd: string = process.cwd()\n): Promise<void> {\n const scope = options.scope || 'local';\n const configCwd = scope === 'global' ? homedir() : cwd;\n\n if (options.mode === 'tui') {\n await setupTuiMode(configCwd, scope, options.configMode);\n } else {\n await setupCliMode(options.agents, configCwd, scope, options.configMode);\n }\n}\n\n// ── helpers ───────────────────────────────────────────────────────────────────\n\n/** Returns true if the agent type is backed by a ConfigGenerator. */\nfunction isGeneratorBacked(agentType: string): boolean {\n return buildConfigGeneratorRegistry().supports(agentType);\n}\n\n/**\n * Configure a single agent according to the chosen config mode.\n * Returns the agentType string on success, null on failure.\n */\nasync function configureOneAgent(\n agentType: AgentType | string,\n configCwd: string,\n scope: 'local' | 'global',\n configMode: McpConfigMode\n): Promise<string | null> {\n try {\n if (configMode === 'agent-config' && isGeneratorBacked(agentType as string)) {\n await generateSkillsMcpAgent(agentType, configCwd, scope);\n } else {\n await configureAgentMcp(agentType, configCwd, scope);\n }\n return agentType as string;\n } catch (error) {\n console.error(\n `✗ Failed to configure ${agents[agentType as AgentType]?.displayName || agentType}:`,\n (error as Error).message\n );\n return null;\n }\n}\n\n/**\n * Print a per-agent summary line after setup, including activation hint\n * when an agent config was written, or a disclaimer for unverified agents.\n */\nfunction printAgentSummary(\n agentType: string,\n configMode: McpConfigMode,\n _scope: 'local' | 'global'\n): void {\n const agent = agents[agentType as AgentType];\n const displayName = agent?.displayName || agentType;\n const isVerified = agent?.agentConfigSupport?.verified ?? false;\n\n if (configMode === 'agent-config' && isGeneratorBacked(agentType)) {\n const hint = agent?.agentConfigSupport?.activationHint;\n console.log(` ✓ ${displayName} — agent config written`);\n if (hint) {\n // Distinguish CLI-command hints (no spaces, or known agent prefixes)\n // from prose hints (GitHub Copilot instructions etc.)\n const looksLikeCli =\n !hint.includes(' ') || hint.startsWith('kiro') || hint.startsWith('opencode');\n if (looksLikeCli) {\n console.log(` → To activate: ${hint}`);\n } else {\n console.log(` → ${hint}`);\n }\n }\n\n // Show disclaimer for unverified agents\n if (!isVerified) {\n console.log(\n ` ⚠️ MCP integration not yet verified. Please ensure ${displayName} picks up the MCP server.`\n );\n }\n } else {\n console.log(` ✓ ${displayName} — MCP server registered in mcp.json`);\n\n // Show disclaimer for unverified agents in mcp-json mode too\n if (!isVerified) {\n console.log(\n ` ⚠️ MCP integration not yet verified. Please check that ${displayName} has loaded the MCP server.`\n );\n }\n }\n}\n\n// ── TUI mode ──────────────────────────────────────────────────────────────────\n\nasync function setupTuiMode(\n cwd: string,\n scope: 'local' | 'global' = 'local',\n forcedConfigMode?: McpConfigMode\n): Promise<void> {\n // 1. Detect installed agents\n const installedAgents = await detectInstalledAgents();\n\n if (installedAgents.length === 0) {\n console.log('No supported agents detected. Please install an agent first.');\n return;\n }\n\n // 2. Choose config scope\n const selectedScope = await select({\n message: 'Where should MCP configs be stored?',\n options: [\n { value: 'local', label: 'Local (Project directory) — shared via Git' },\n { value: 'global', label: 'Global (Home directory) — personal settings only' },\n ],\n });\n\n if (typeof selectedScope === 'symbol') {\n cancel('Operation cancelled');\n return;\n }\n\n scope = selectedScope as 'local' | 'global';\n const configCwd = scope === 'global' ? homedir() : cwd;\n\n // 3. Select agents — label generator-capable ones so the user knows\n const selectedAgents = await multiselect({\n message: 'Select agents to configure for MCP:',\n options: installedAgents.map((agentType) => {\n const agent = agents[agentType];\n const supportsAgentConfig = !!agent?.agentConfigSupport;\n return {\n value: agentType as any,\n label: `${agent?.displayName || agentType}${supportsAgentConfig ? ' ✦' : ''}`,\n hint: supportsAgentConfig ? 'supports agent config' : undefined,\n };\n }),\n });\n\n if (typeof selectedAgents === 'symbol') {\n cancel('Operation cancelled');\n return;\n }\n\n if (!selectedAgents || selectedAgents.length === 0) {\n console.log('No agents selected.');\n return;\n }\n\n // 4. If at least one selected agent supports an agent config, ask the user\n // whether they want agent-config or plain mcp.json — unless the user\n // already passed --agent-config or --mcp-json on the command line.\n const agentConfigCapable = (selectedAgents as AgentType[]).filter((a) =>\n isGeneratorBacked(a as string)\n );\n\n let configMode: McpConfigMode = 'mcp-json';\n\n if (forcedConfigMode) {\n // CLI flag takes precedence — skip the prompt entirely\n configMode = forcedConfigMode;\n } else if (agentConfigCapable.length > 0) {\n const capableNames = agentConfigCapable\n .map((a) => agents[a as AgentType]?.displayName || a)\n .join(', ');\n\n const modeChoice = await select({\n message: `How should skills-mcp be configured for ${capableNames}?`,\n options: [\n {\n value: 'agent-config' as McpConfigMode,\n label: 'Agent config — creates a named \"skills-mcp\" agent with usage instructions',\n hint: 'Recommended: selectable by name; bundled prompt guides the agent',\n },\n {\n value: 'mcp-json' as McpConfigMode,\n label: 'MCP server only — registers servers in mcp.json, no dedicated agent',\n hint: 'Simpler; MCP server is available in all conversations without a named agent',\n },\n ],\n });\n\n if (typeof modeChoice === 'symbol') {\n cancel('Operation cancelled');\n return;\n }\n\n configMode = modeChoice as McpConfigMode;\n }\n\n // 5. Configure each selected agent\n console.log('');\n const configuredAgents: AgentType[] = [];\n\n for (const agentType of selectedAgents) {\n const result = await configureOneAgent(agentType as AgentType, configCwd, scope, configMode);\n if (result !== null) configuredAgents.push(agentType as AgentType);\n }\n\n // 6. Inject skill-required MCP servers\n if (configuredAgents.length > 0) {\n const skillDeps = await loadInstalledSkillMcpDeps(cwd, scope);\n await configureSkillMcpDepsForAgents(skillDeps, configuredAgents, configCwd, scope, configMode);\n }\n\n // 7. Per-agent summary with activation hints\n const scopeLabel = scope === 'global' ? 'global (home directory)' : 'local (project directory)';\n const failCount = selectedAgents.length - configuredAgents.length;\n\n console.log('');\n if (configuredAgents.length > 0) {\n console.log(`Configured ${configuredAgents.length} agent(s) in ${scopeLabel}:`);\n for (const agentType of configuredAgents) {\n printAgentSummary(agentType as string, configMode, scope);\n }\n }\n if (failCount > 0) {\n console.error(`\\n✗ Failed to configure ${failCount} agent(s) in ${scopeLabel}`);\n }\n}\n\n// ── CLI mode ──────────────────────────────────────────────────────────────────\n\n/**\n * CLI (non-interactive) mode. Generator-backed agents get agent-config by default.\n */\nasync function setupCliMode(\n agentTypes: AgentType[],\n cwd: string,\n scope: 'local' | 'global' = 'local',\n forcedConfigMode?: McpConfigMode\n): Promise<void> {\n if (agentTypes.includes('*' as AgentType)) {\n const installedAgents = await detectInstalledAgents();\n agentTypes = installedAgents;\n }\n\n const configuredAgents: AgentType[] = [];\n\n for (const agentType of agentTypes) {\n // Honour the forced mode if set; otherwise default to agent-config for\n // generator-backed agents and mcp-json for all others.\n const configMode: McpConfigMode =\n forcedConfigMode ?? (isGeneratorBacked(agentType) ? 'agent-config' : 'mcp-json');\n const result = await configureOneAgent(agentType, cwd, scope, configMode);\n if (result !== null) configuredAgents.push(agentType);\n }\n\n // Inject skill-required MCP servers, routing each agent to its effective mode\n if (configuredAgents.length > 0) {\n const skillDeps = await loadInstalledSkillMcpDeps(cwd, scope);\n\n if (forcedConfigMode) {\n // Single forced mode — split only on generator capability\n const generatorBacked = configuredAgents.filter((a) => isGeneratorBacked(a));\n const rawMcp = configuredAgents.filter((a) => !isGeneratorBacked(a));\n if (generatorBacked.length > 0) {\n await configureSkillMcpDepsForAgents(\n skillDeps,\n generatorBacked,\n cwd,\n scope,\n forcedConfigMode\n );\n }\n if (rawMcp.length > 0) {\n await configureSkillMcpDepsForAgents(skillDeps, rawMcp, cwd, scope, 'mcp-json');\n }\n } else {\n // Auto mode — use natural mode per agent\n const generatorBacked = configuredAgents.filter((a) => isGeneratorBacked(a));\n const rawMcp = configuredAgents.filter((a) => !isGeneratorBacked(a));\n if (generatorBacked.length > 0) {\n await configureSkillMcpDepsForAgents(\n skillDeps,\n generatorBacked,\n cwd,\n scope,\n 'agent-config'\n );\n }\n if (rawMcp.length > 0) {\n await configureSkillMcpDepsForAgents(skillDeps, rawMcp, cwd, scope, 'mcp-json');\n }\n }\n }\n\n // Summary\n const failCount = agentTypes.length - configuredAgents.length;\n if (configuredAgents.length > 0) {\n console.log(`\\nConfigured ${configuredAgents.length} agent(s):`);\n for (const agentType of configuredAgents) {\n const configMode: McpConfigMode =\n forcedConfigMode ?? (isGeneratorBacked(agentType) ? 'agent-config' : 'mcp-json');\n printAgentSummary(agentType as string, configMode, scope);\n }\n }\n if (failCount > 0) {\n console.error(`\\n✗ Failed to configure ${failCount} agent(s)`);\n }\n}\n","#!/usr/bin/env node\n\nimport { spawn, spawnSync } from 'child_process';\nimport { writeFileSync, readFileSync, existsSync, mkdirSync, readdirSync, statSync } from 'fs';\nimport { basename, join, dirname } from 'path';\nimport { homedir } from 'os';\nimport { createHash } from 'crypto';\nimport { fileURLToPath } from 'url';\nimport { runAdd, parseAddOptions, initTelemetry } from './add.ts';\nimport { runFind } from './find.ts';\nimport { runInstallFromLock } from './install.ts';\nimport { runList } from './list.ts';\nimport { removeCommand, parseRemoveOptions } from './remove.ts';\nimport { runSync, parseSyncOptions } from './sync.ts';\nimport { track } from './telemetry.ts';\nimport { fetchSkillFolderHash, getGitHubToken } from './skill-lock.ts';\nimport { runMcpSetup, parseMcpOptions } from './mcp.ts';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\nfunction getVersion(): string {\n try {\n const pkgPath = join(__dirname, '..', 'package.json');\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));\n return pkg.version;\n } catch {\n return '0.0.0';\n }\n}\n\nconst VERSION = getVersion();\ninitTelemetry(VERSION);\n\nconst RESET = '\\x1b[0m';\nconst BOLD = '\\x1b[1m';\n// 256-color grays - visible on both light and dark backgrounds\nconst DIM = '\\x1b[38;5;102m'; // darker gray for secondary text\nconst TEXT = '\\x1b[38;5;145m'; // lighter gray for primary text\n\nconst LOGO_LINES = [\n '███████╗██╗ ██╗██╗██╗ ██╗ ███████╗ ███╗ ███╗ ██████╗██████╗ ',\n '██╔════╝██║ ██╔╝██║██║ ██║ ██╔════╝ ████╗ ████║██╔════╝██╔══██╗',\n '███████╗█████╔╝ ██║██║ ██║ ███████╗█████╗██╔████╔██║██║ ██████╔╝',\n '╚════██║██╔═██╗ ██║██║ ██║ ╚════██║╚════╝██║╚██╔╝██║██║ ██╔═══╝ ',\n '███████║██║ ██╗██║███████╗███████╗███████║ ██║ ╚═╝ ██║╚██████╗██║ ',\n '╚══════╝╚═╝ ╚═╝╚═╝╚══════╝╚══════╝╚══════╝ ╚═╝ ╚═╝ ╚═════╝╚═╝ ',\n];\n\n// 256-color middle grays - visible on both light and dark backgrounds\nconst GRAYS = [\n '\\x1b[38;5;250m', // lighter gray\n '\\x1b[38;5;248m',\n '\\x1b[38;5;245m', // mid gray\n '\\x1b[38;5;243m',\n '\\x1b[38;5;240m',\n '\\x1b[38;5;238m', // darker gray\n];\n\nfunction showLogo(): void {\n console.log();\n LOGO_LINES.forEach((line, i) => {\n console.log(`${GRAYS[i]}${line}${RESET}`);\n });\n}\n\nfunction showBanner(): void {\n showLogo();\n console.log();\n console.log(`${DIM}The open agent skills ecosystem${RESET}`);\n console.log();\n console.log(\n ` ${DIM}$${RESET} ${TEXT}npx skills add ${DIM}<package>${RESET} ${DIM}Add a new skill${RESET}`\n );\n console.log(\n ` ${DIM}$${RESET} ${TEXT}npx skills remove${RESET} ${DIM}Remove installed skills${RESET}`\n );\n console.log(\n ` ${DIM}$${RESET} ${TEXT}npx skills list${RESET} ${DIM}List installed skills${RESET}`\n );\n console.log(\n ` ${DIM}$${RESET} ${TEXT}npx skills find ${DIM}[query]${RESET} ${DIM}Search for skills${RESET}`\n );\n console.log();\n console.log(\n ` ${DIM}$${RESET} ${TEXT}npx skills check${RESET} ${DIM}Check for updates${RESET}`\n );\n console.log(\n ` ${DIM}$${RESET} ${TEXT}npx skills update${RESET} ${DIM}Update all skills${RESET}`\n );\n console.log();\n console.log(\n ` ${DIM}$${RESET} ${TEXT}npx skills experimental_install${RESET} ${DIM}Restore from skills-lock.json${RESET}`\n );\n console.log(\n ` ${DIM}$${RESET} ${TEXT}npx skills init ${DIM}[name]${RESET} ${DIM}Create a new skill${RESET}`\n );\n console.log(\n ` ${DIM}$${RESET} ${TEXT}npx skills experimental_sync${RESET} ${DIM}Sync skills from node_modules${RESET}`\n );\n console.log();\n console.log(`${DIM}try:${RESET} npx skills add vercel-labs/agent-skills`);\n console.log();\n console.log(`Discover more skills at ${TEXT}https://skills.sh/${RESET}`);\n console.log();\n}\n\nfunction showHelp(): void {\n console.log(`\n${BOLD}Usage:${RESET} skills <command> [options]\n\n${BOLD}Manage Skills:${RESET}\n add <package> Add a skill package (alias: a)\n e.g. vercel-labs/agent-skills\n https://github.com/vercel-labs/agent-skills\n remove [skills] Remove installed skills\n list, ls List installed skills\n find [query] Search for skills interactively\n\n${BOLD}Updates:${RESET}\n check Check for available skill updates\n update Update all skills to latest versions\n\n${BOLD}Project:${RESET}\n experimental_install Restore skills from skills-lock.json\n init [name] Initialize a skill (creates <name>/SKILL.md or ./SKILL.md)\n experimental_sync Sync skills from node_modules into agent directories\n\n${BOLD}Add Options:${RESET}\n -g, --global Install skill globally (user-level) instead of project-level\n -a, --agent <agents> Specify agents to install to (use '*' for all agents)\n -s, --skill <skills> Specify skill names to install (use '*' for all skills)\n -l, --list List available skills in the repository without installing\n -y, --yes Skip confirmation prompts\n --copy Copy files instead of symlinking to agent directories\n --all Shorthand for --skill '*' --agent '*' -y\n --full-depth Search all subdirectories even when a root SKILL.md exists\n\n${BOLD}Remove Options:${RESET}\n -g, --global Remove from global scope\n -a, --agent <agents> Remove from specific agents (use '*' for all agents)\n -s, --skill <skills> Specify skills to remove (use '*' for all skills)\n -y, --yes Skip confirmation prompts\n --all Shorthand for --skill '*' --agent '*' -y\n \n${BOLD}Experimental Sync Options:${RESET}\n -a, --agent <agents> Specify agents to install to (use '*' for all agents)\n -y, --yes Skip confirmation prompts\n\n${BOLD}List Options:${RESET}\n -g, --global List global skills (default: project)\n -a, --agent <agents> Filter by specific agents\n\n${BOLD}Options:${RESET}\n --help, -h Show this help message\n --version, -v Show version number\n\n${BOLD}Examples:${RESET}\n ${DIM}$${RESET} skills add vercel-labs/agent-skills\n ${DIM}$${RESET} skills add vercel-labs/agent-skills -g\n ${DIM}$${RESET} skills add vercel-labs/agent-skills --agent claude-code cursor\n ${DIM}$${RESET} skills add vercel-labs/agent-skills --skill pr-review commit\n ${DIM}$${RESET} skills remove ${DIM}# interactive remove${RESET}\n ${DIM}$${RESET} skills remove web-design ${DIM}# remove by name${RESET}\n ${DIM}$${RESET} skills rm --global frontend-design\n ${DIM}$${RESET} skills list ${DIM}# list project skills${RESET}\n ${DIM}$${RESET} skills ls -g ${DIM}# list global skills${RESET}\n ${DIM}$${RESET} skills ls -a claude-code ${DIM}# filter by agent${RESET}\n ${DIM}$${RESET} skills find ${DIM}# interactive search${RESET}\n ${DIM}$${RESET} skills find typescript ${DIM}# search by keyword${RESET}\n ${DIM}$${RESET} skills check\n ${DIM}$${RESET} skills update\n ${DIM}$${RESET} skills experimental_install ${DIM}# restore from skills-lock.json${RESET}\n ${DIM}$${RESET} skills init my-skill\n ${DIM}$${RESET} skills experimental_sync ${DIM}# sync from node_modules${RESET}\n ${DIM}$${RESET} skills experimental_sync -y ${DIM}# sync without prompts${RESET}\n\nDiscover more skills at ${TEXT}https://skills.sh/${RESET}\n`);\n}\n\nfunction showRemoveHelp(): void {\n console.log(`\n${BOLD}Usage:${RESET} skills remove [skills...] [options]\n\n${BOLD}Description:${RESET}\n Remove installed skills from agents. If no skill names are provided,\n an interactive selection menu will be shown.\n\n${BOLD}Arguments:${RESET}\n skills Optional skill names to remove (space-separated)\n\n${BOLD}Options:${RESET}\n -g, --global Remove from global scope (~/) instead of project scope\n -a, --agent Remove from specific agents (use '*' for all agents)\n -s, --skill Specify skills to remove (use '*' for all skills)\n -y, --yes Skip confirmation prompts\n --all Shorthand for --skill '*' --agent '*' -y\n\n${BOLD}Examples:${RESET}\n ${DIM}$${RESET} skills remove ${DIM}# interactive selection${RESET}\n ${DIM}$${RESET} skills remove my-skill ${DIM}# remove specific skill${RESET}\n ${DIM}$${RESET} skills remove skill1 skill2 -y ${DIM}# remove multiple skills${RESET}\n ${DIM}$${RESET} skills remove --global my-skill ${DIM}# remove from global scope${RESET}\n ${DIM}$${RESET} skills rm --agent claude-code my-skill ${DIM}# remove from specific agent${RESET}\n ${DIM}$${RESET} skills remove --all ${DIM}# remove all skills${RESET}\n ${DIM}$${RESET} skills remove --skill '*' -a cursor ${DIM}# remove all skills from cursor${RESET}\n\nDiscover more skills at ${TEXT}https://skills.sh/${RESET}\n`);\n}\n\nfunction showMcpHelp(): void {\n console.log(`\n${BOLD}Usage:${RESET} skills mcp setup [options]\n\n${BOLD}Description:${RESET}\n Configure MCP (Model Context Protocol) server for agent environments.\n Supports both interactive (TUI) and command-line (CLI) modes.\n\n${BOLD}Subcommands:${RESET}\n setup Configure MCP server for agents (default if no subcommand)\n\n${BOLD}Options:${RESET}\n -a, --agent Specify agents to configure (space-separated)\n Use '*' to configure all detected agents\n -g, --global Write configs to home directory instead of project\n --agent-config Create a named agent file with usage instructions\n (Kiro, GitHub Copilot, OpenCode only; default for those agents)\n --mcp-json Register MCP servers in mcp.json only, no agent file\n (works for all agents; skips the TUI mode-selection prompt)\n\n${BOLD}Modes:${RESET}\n ${DIM}Interactive (TUI):${RESET} skills mcp setup\n Guides through scope → agent selection → config type → summary\n\n ${DIM}Command-line (CLI):${RESET} skills mcp setup --agent <agents>\n Configures specified agents without interaction\n\n${BOLD}Examples:${RESET}\n ${DIM}$${RESET} skills mcp setup ${DIM}# interactive${RESET}\n ${DIM}$${RESET} skills mcp setup --agent claude-code ${DIM}# mcp.json for Claude${RESET}\n ${DIM}$${RESET} skills mcp setup --agent kiro-cli --agent-config ${DIM}# Kiro agent file${RESET}\n ${DIM}$${RESET} skills mcp setup --agent kiro-cli --mcp-json ${DIM}# Kiro mcp.json only${RESET}\n ${DIM}$${RESET} skills mcp setup --agent claude-code cline --mcp-json ${DIM}# multiple, mcp.json${RESET}\n ${DIM}$${RESET} skills mcp setup --agent '*' ${DIM}# all agents${RESET}\n\n${BOLD}Supported Agents:${RESET}\n claude-code, cline, cursor, kiro-cli, junie, opencode, and more\n Agents marked ✦ in the TUI support a rich agent config file.\n\nDiscover more at ${TEXT}https://skills.sh/${RESET}\n`);\n}\n\nfunction runInit(args: string[]): void {\n const cwd = process.cwd();\n const skillName = args[0] || basename(cwd);\n const hasName = args[0] !== undefined;\n\n const skillDir = hasName ? join(cwd, skillName) : cwd;\n const skillFile = join(skillDir, 'SKILL.md');\n const displayPath = hasName ? `${skillName}/SKILL.md` : 'SKILL.md';\n\n if (existsSync(skillFile)) {\n console.log(`${TEXT}Skill already exists at ${DIM}${displayPath}${RESET}`);\n return;\n }\n\n if (hasName) {\n mkdirSync(skillDir, { recursive: true });\n }\n\n const skillContent = `---\nname: ${skillName}\ndescription: A brief description of what this skill does\n---\n\n# ${skillName}\n\nInstructions for the agent to follow when this skill is activated.\n\n## When to use\n\nDescribe when this skill should be used.\n\n## Instructions\n\n1. First step\n2. Second step\n3. Additional steps as needed\n`;\n\n writeFileSync(skillFile, skillContent);\n\n console.log(`${TEXT}Initialized skill: ${DIM}${skillName}${RESET}`);\n console.log();\n console.log(`${DIM}Created:${RESET}`);\n console.log(` ${displayPath}`);\n console.log();\n console.log(`${DIM}Next steps:${RESET}`);\n console.log(` 1. Edit ${TEXT}${displayPath}${RESET} to define your skill instructions`);\n console.log(\n ` 2. Update the ${TEXT}name${RESET} and ${TEXT}description${RESET} in the frontmatter`\n );\n console.log();\n console.log(`${DIM}Publishing:${RESET}`);\n console.log(\n ` ${DIM}GitHub:${RESET} Push to a repo, then ${TEXT}npx skills add <owner>/<repo>${RESET}`\n );\n console.log(\n ` ${DIM}URL:${RESET} Host the file, then ${TEXT}npx skills add https://example.com/${displayPath}${RESET}`\n );\n console.log();\n console.log(`Browse existing skills for inspiration at ${TEXT}https://skills.sh/${RESET}`);\n console.log();\n}\n\n// ============================================\n// Check and Update Commands\n// ============================================\n\nconst AGENTS_DIR = '.agents';\nconst LOCK_FILE = '.skill-lock.json';\nconst CHECK_UPDATES_API_URL = 'https://add-skill.vercel.sh/check-updates';\nconst CURRENT_LOCK_VERSION = 3; // Bumped from 2 to 3 for folder hash support\n\ninterface SkillLockEntry {\n source: string;\n sourceType: string;\n sourceUrl: string;\n skillPath?: string;\n /** GitHub tree SHA for the entire skill folder (v3) */\n skillFolderHash: string;\n installedAt: string;\n updatedAt: string;\n}\n\ninterface SkillLockFile {\n version: number;\n skills: Record<string, SkillLockEntry>;\n}\n\ninterface CheckUpdatesRequest {\n skills: Array<{\n name: string;\n source: string;\n path?: string;\n skillFolderHash: string;\n }>;\n}\n\ninterface CheckUpdatesResponse {\n updates: Array<{\n name: string;\n source: string;\n currentHash: string;\n latestHash: string;\n }>;\n errors?: Array<{\n name: string;\n source: string;\n error: string;\n }>;\n}\n\nfunction getSkillLockPath(): string {\n return join(homedir(), AGENTS_DIR, LOCK_FILE);\n}\n\nfunction readSkillLock(): SkillLockFile {\n const lockPath = getSkillLockPath();\n try {\n const content = readFileSync(lockPath, 'utf-8');\n const parsed = JSON.parse(content) as SkillLockFile;\n if (typeof parsed.version !== 'number' || !parsed.skills) {\n return { version: CURRENT_LOCK_VERSION, skills: {} };\n }\n // If old version, wipe and start fresh (backwards incompatible change)\n // v3 adds skillFolderHash - we want fresh installs to populate it\n if (parsed.version < CURRENT_LOCK_VERSION) {\n return { version: CURRENT_LOCK_VERSION, skills: {} };\n }\n return parsed;\n } catch {\n return { version: CURRENT_LOCK_VERSION, skills: {} };\n }\n}\n\nfunction writeSkillLock(lock: SkillLockFile): void {\n const lockPath = getSkillLockPath();\n const dir = join(homedir(), AGENTS_DIR);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n writeFileSync(lockPath, JSON.stringify(lock, null, 2), 'utf-8');\n}\n\nasync function runCheck(args: string[] = []): Promise<void> {\n console.log(`${TEXT}Checking for skill updates...${RESET}`);\n console.log();\n\n const lock = readSkillLock();\n const skillNames = Object.keys(lock.skills);\n\n if (skillNames.length === 0) {\n console.log(`${DIM}No skills tracked in lock file.${RESET}`);\n console.log(`${DIM}Install skills with${RESET} ${TEXT}npx skills add <package>${RESET}`);\n return;\n }\n\n // Get GitHub token from user's environment for higher rate limits\n const token = getGitHubToken();\n\n // Group skills by source (owner/repo) to batch GitHub API calls\n const skillsBySource = new Map<string, Array<{ name: string; entry: SkillLockEntry }>>();\n let skippedCount = 0;\n\n for (const skillName of skillNames) {\n const entry = lock.skills[skillName];\n if (!entry) continue;\n\n // Only check GitHub-sourced skills with folder hash\n if (entry.sourceType !== 'github' || !entry.skillFolderHash || !entry.skillPath) {\n skippedCount++;\n continue;\n }\n\n const existing = skillsBySource.get(entry.source) || [];\n existing.push({ name: skillName, entry });\n skillsBySource.set(entry.source, existing);\n }\n\n const totalSkills = skillNames.length - skippedCount;\n if (totalSkills === 0) {\n console.log(`${DIM}No GitHub skills to check.${RESET}`);\n return;\n }\n\n console.log(`${DIM}Checking ${totalSkills} skill(s) for updates...${RESET}`);\n\n const updates: Array<{ name: string; source: string }> = [];\n const errors: Array<{ name: string; source: string; error: string }> = [];\n\n // Check each source (one API call per repo)\n for (const [source, skills] of skillsBySource) {\n for (const { name, entry } of skills) {\n try {\n const latestHash = await fetchSkillFolderHash(source, entry.skillPath!, token);\n\n if (!latestHash) {\n errors.push({ name, source, error: 'Could not fetch from GitHub' });\n continue;\n }\n\n if (latestHash !== entry.skillFolderHash) {\n updates.push({ name, source });\n }\n } catch (err) {\n errors.push({\n name,\n source,\n error: err instanceof Error ? err.message : 'Unknown error',\n });\n }\n }\n }\n\n console.log();\n\n if (updates.length === 0) {\n console.log(`${TEXT}✓ All skills are up to date${RESET}`);\n } else {\n console.log(`${TEXT}${updates.length} update(s) available:${RESET}`);\n console.log();\n for (const update of updates) {\n console.log(` ${TEXT}↑${RESET} ${update.name}`);\n console.log(` ${DIM}source: ${update.source}${RESET}`);\n }\n console.log();\n console.log(\n `${DIM}Run${RESET} ${TEXT}npx skills update${RESET} ${DIM}to update all skills${RESET}`\n );\n }\n\n if (errors.length > 0) {\n console.log();\n console.log(`${DIM}Could not check ${errors.length} skill(s) (may need reinstall)${RESET}`);\n }\n\n // Track telemetry\n track({\n event: 'check',\n skillCount: String(totalSkills),\n updatesAvailable: String(updates.length),\n });\n\n console.log();\n}\n\nasync function runUpdate(): Promise<void> {\n console.log(`${TEXT}Checking for skill updates...${RESET}`);\n console.log();\n\n const lock = readSkillLock();\n const skillNames = Object.keys(lock.skills);\n\n if (skillNames.length === 0) {\n console.log(`${DIM}No skills tracked in lock file.${RESET}`);\n console.log(`${DIM}Install skills with${RESET} ${TEXT}npx skills add <package>${RESET}`);\n return;\n }\n\n // Get GitHub token from user's environment for higher rate limits\n const token = getGitHubToken();\n\n // Find skills that need updates by checking GitHub directly\n const updates: Array<{ name: string; source: string; entry: SkillLockEntry }> = [];\n let checkedCount = 0;\n\n for (const skillName of skillNames) {\n const entry = lock.skills[skillName];\n if (!entry) continue;\n\n // Only check GitHub-sourced skills with folder hash\n if (entry.sourceType !== 'github' || !entry.skillFolderHash || !entry.skillPath) {\n continue;\n }\n\n checkedCount++;\n\n try {\n const latestHash = await fetchSkillFolderHash(entry.source, entry.skillPath, token);\n\n if (latestHash && latestHash !== entry.skillFolderHash) {\n updates.push({ name: skillName, source: entry.source, entry });\n }\n } catch {\n // Skip skills that fail to check\n }\n }\n\n if (checkedCount === 0) {\n console.log(`${DIM}No skills to check.${RESET}`);\n return;\n }\n\n if (updates.length === 0) {\n console.log(`${TEXT}✓ All skills are up to date${RESET}`);\n console.log();\n return;\n }\n\n console.log(`${TEXT}Found ${updates.length} update(s)${RESET}`);\n console.log();\n\n // Reinstall each skill that has an update\n let successCount = 0;\n let failCount = 0;\n\n for (const update of updates) {\n console.log(`${TEXT}Updating ${update.name}...${RESET}`);\n\n // Build the URL with subpath to target the specific skill directory\n // e.g., https://github.com/owner/repo/tree/main/skills/my-skill\n let installUrl = update.entry.sourceUrl;\n if (update.entry.skillPath) {\n // Extract the skill folder path (remove /SKILL.md suffix)\n let skillFolder = update.entry.skillPath;\n if (skillFolder.endsWith('/SKILL.md')) {\n skillFolder = skillFolder.slice(0, -9);\n } else if (skillFolder.endsWith('SKILL.md')) {\n skillFolder = skillFolder.slice(0, -8);\n }\n if (skillFolder.endsWith('/')) {\n skillFolder = skillFolder.slice(0, -1);\n }\n\n // Convert git URL to tree URL with path\n // https://github.com/owner/repo.git -> https://github.com/owner/repo/tree/main/path\n installUrl = update.entry.sourceUrl.replace(/\\.git$/, '').replace(/\\/$/, '');\n installUrl = `${installUrl}/tree/main/${skillFolder}`;\n }\n\n // Use skills CLI to reinstall with -g -y flags\n const result = spawnSync('npx', ['-y', 'skills', 'add', installUrl, '-g', '-y'], {\n stdio: ['inherit', 'pipe', 'pipe'],\n });\n\n if (result.status === 0) {\n successCount++;\n console.log(` ${TEXT}✓${RESET} Updated ${update.name}`);\n } else {\n failCount++;\n console.log(` ${DIM}✗ Failed to update ${update.name}${RESET}`);\n }\n }\n\n console.log();\n if (successCount > 0) {\n console.log(`${TEXT}✓ Updated ${successCount} skill(s)${RESET}`);\n }\n if (failCount > 0) {\n console.log(`${DIM}Failed to update ${failCount} skill(s)${RESET}`);\n }\n\n // Track telemetry\n track({\n event: 'update',\n skillCount: String(updates.length),\n successCount: String(successCount),\n failCount: String(failCount),\n });\n\n console.log();\n}\n\n// ============================================\n// Main\n// ============================================\n\nasync function main(): Promise<void> {\n const args = process.argv.slice(2);\n\n if (args.length === 0) {\n showBanner();\n return;\n }\n\n const command = args[0];\n const restArgs = args.slice(1);\n\n switch (command) {\n case 'find':\n case 'search':\n case 'f':\n case 's':\n showLogo();\n console.log();\n await runFind(restArgs);\n break;\n case 'init':\n showLogo();\n console.log();\n runInit(restArgs);\n break;\n case 'experimental_install': {\n showLogo();\n await runInstallFromLock(restArgs);\n break;\n }\n case 'i':\n case 'install':\n case 'a':\n case 'add': {\n showLogo();\n const { source: addSource, options: addOpts } = parseAddOptions(restArgs);\n await runAdd(addSource, addOpts);\n break;\n }\n case 'remove':\n case 'rm':\n case 'r':\n // Check for --help or -h flag\n if (restArgs.includes('--help') || restArgs.includes('-h')) {\n showRemoveHelp();\n break;\n }\n const { skills, options: removeOptions } = parseRemoveOptions(restArgs);\n await removeCommand(skills, removeOptions);\n break;\n case 'experimental_sync': {\n showLogo();\n const { options: syncOptions } = parseSyncOptions(restArgs);\n await runSync(restArgs, syncOptions);\n break;\n }\n case 'list':\n case 'ls':\n await runList(restArgs);\n break;\n case 'check':\n runCheck(restArgs);\n break;\n case 'update':\n case 'upgrade':\n runUpdate();\n break;\n case 'mcp': {\n if (!restArgs[0] || restArgs[0] === '--help' || restArgs[0] === '-h') {\n showMcpHelp();\n break;\n }\n const subcommand = restArgs[0];\n const mcpArgs = restArgs.slice(1);\n\n if (subcommand === 'setup') {\n showLogo();\n const options = parseMcpOptions(mcpArgs);\n await runMcpSetup(options);\n } else {\n console.error(`Unknown mcp subcommand: ${subcommand}`);\n showMcpHelp();\n }\n break;\n }\n case '--help':\n case '-h':\n showHelp();\n break;\n case '--version':\n case '-v':\n console.log(VERSION);\n break;\n\n default:\n console.log(`Unknown command: ${command}`);\n console.log(`Run ${BOLD}skills --help${RESET} for usage.`);\n }\n}\n\nmain();\n"],"mappings":"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"}