skilldex 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/cli/index.ts","../../src/lib/config.ts","../../src/lib/constants.ts","../../src/lib/scanner.ts","../../src/lib/agents.ts","../../src/lib/writer.ts","../../src/lib/indexer.ts","../../src/lib/add.ts","../../src/lib/init.ts","../../src/lib/list.ts","../../src/lib/remove.ts","../../src/lib/sync.ts","../../src/cli/format.ts"],"sourcesContent":["import * as p from \"@clack/prompts\";\nimport { Command } from \"commander\";\nimport pc from \"picocolors\";\nimport { addSkill } from \"../lib/add.js\";\nimport { getAgentDisplayName } from \"../lib/agents.js\";\nimport { readConfig } from \"../lib/config.js\";\nimport { TARGET_FILE } from \"../lib/constants.js\";\nimport { initWithSkills } from \"../lib/init.js\";\nimport { listSkills } from \"../lib/list.js\";\nimport { removeSkill } from \"../lib/remove.js\";\nimport { scanForSkills } from \"../lib/scanner.js\";\nimport { syncSkills } from \"../lib/sync.js\";\nimport { formatSkillPath, handleCommandError, logContextSize, pluralize } from \"./format.js\";\n\nconst program = new Command();\n\nprogram\n .name(\"skilldex\")\n .description(\"Index AI agent skills into passive context (AGENTS.md)\")\n .version(\"0.1.0\");\n\nprogram\n .command(\"init\")\n .description(\"Initialize skilldex in the current project\")\n .option(\"-y, --yes\", \"Skip prompts and index all discovered skills\")\n .option(\"-t, --target <files...>\", \"Target file(s) to write index to\")\n .action(async (opts: { yes?: boolean; target?: string[] }) => {\n p.intro(pc.bgCyan(pc.black(\" skilldex init \")));\n\n const projectRoot = process.cwd();\n const skills = await scanForSkills(projectRoot);\n\n if (skills.length === 0) {\n p.outro(pc.yellow(\"No skills found in any agent skills directory.\"));\n return;\n }\n\n // Determine target files\n let targets: string[];\n if (opts.target) {\n targets = opts.target;\n } else if (opts.yes) {\n targets = [TARGET_FILE];\n } else {\n const selected = await p.multiselect({\n message: \"Select target file(s)\",\n options: [\n { value: \"AGENTS.md\", label: \"AGENTS.md\", hint: \"default\" },\n { value: \"CLAUDE.md\", label: \"CLAUDE.md\" },\n { value: \"__custom__\", label: \"Custom...\" },\n ],\n initialValues: [\"AGENTS.md\"],\n required: true,\n });\n\n if (p.isCancel(selected)) {\n p.cancel(\"Init cancelled.\");\n process.exit(0);\n }\n\n targets = selected.filter((v) => v !== \"__custom__\");\n\n if (selected.includes(\"__custom__\")) {\n const custom = await p.text({\n message: \"Enter target filename\",\n placeholder: \"AGENTS.md\",\n validate: (value) => {\n if (!value?.trim()) return \"Filename is required\";\n },\n });\n\n if (p.isCancel(custom)) {\n p.cancel(\"Init cancelled.\");\n process.exit(0);\n }\n\n targets.push(custom);\n }\n }\n\n // Detect name collisions for hint display\n const nameCount = new Map<string, number>();\n for (const s of skills) {\n nameCount.set(s.name, (nameCount.get(s.name) ?? 0) + 1);\n }\n\n let selectedSkillPaths: string[];\n\n if (opts.yes) {\n p.log.info(\n `Found ${skills.length} ${pluralize(skills.length, \"skill\", \"skills\")}, indexing all (--yes)`,\n );\n selectedSkillPaths = skills.map((s) => s.relativePath);\n } else {\n const selected = await p.multiselect({\n message: \"Select skills to index\",\n options: skills.map((s) => {\n const relPath = s.relativePath;\n const hasCollision = (nameCount.get(s.name) ?? 0) > 1;\n if (hasCollision) {\n const agent = getAgentDisplayName(relPath);\n const label = agent ? `${s.name} - ${agent}` : s.name;\n return { value: relPath, label, hint: relPath };\n }\n return { value: relPath, label: s.name, hint: s.description || undefined };\n }),\n initialValues: skills.map((s) => s.relativePath),\n required: true,\n });\n\n if (p.isCancel(selected)) {\n p.cancel(\"Init cancelled.\");\n process.exit(0);\n }\n\n selectedSkillPaths = selected;\n }\n\n const selectedSkills = skills.filter((s) => selectedSkillPaths.includes(s.relativePath));\n const result = await initWithSkills(projectRoot, selectedSkills, targets);\n\n logContextSize(result.managedSize, result.targets);\n p.outro(\n pc.green(\n `Indexed ${result.skillCount} ${pluralize(result.skillCount, \"skill\", \"skills\")} into ${result.targets.map((t) => t.file).join(\", \")}`,\n ),\n );\n });\n\nprogram\n .command(\"add <skill>\")\n .description(\"Add a skill to the project\")\n .action(async (skillName: string) => {\n p.intro(pc.bgCyan(pc.black(\" skilldex add \")));\n\n const projectRoot = process.cwd();\n const s = p.spinner();\n\n try {\n // Disambiguate name-based input before calling addSkill\n let resolvedName = skillName;\n\n if (!skillName.includes(\"/\")) {\n const allSkills = await scanForSkills(projectRoot);\n const matches = allSkills.filter((sk) => sk.name === skillName);\n\n if (matches.length > 1) {\n const config = await readConfig(projectRoot);\n const indexedPaths = new Set(config.skills.map((sk) => sk.path));\n const available = matches.filter((sk) => !indexedPaths.has(sk.relativePath));\n\n if (available.length === 0) {\n p.outro(pc.yellow(`All skills named \"${skillName}\" are already indexed.`));\n return;\n }\n\n const selected = await p.select({\n message: `Multiple skills named \"${skillName}\" found. Which one?`,\n options: matches\n .map((sk) => {\n const indexed = indexedPaths.has(sk.relativePath);\n const agent = getAgentDisplayName(sk.relativePath);\n return {\n value: sk.relativePath,\n label: agent ?? sk.relativePath,\n hint: indexed ? \"already indexed\" : sk.relativePath,\n disabled: indexed,\n };\n })\n .sort((a, b) => {\n if (a.disabled !== b.disabled) return a.disabled ? -1 : 1;\n return a.label.localeCompare(b.label);\n }),\n });\n\n if (p.isCancel(selected)) {\n p.cancel(\"Add cancelled.\");\n process.exit(0);\n }\n\n resolvedName = selected;\n }\n }\n\n s.start(\"Adding skill...\");\n const result = await addSkill(projectRoot, resolvedName);\n s.stop(\"✓ Skill added\");\n\n logContextSize(result.managedSize, result.targets);\n p.outro(\n pc.green(`Added \"${result.skillName}\" to ${result.targets.map((t) => t.file).join(\", \")}`),\n );\n } catch (error) {\n handleCommandError(error, s);\n }\n });\n\nprogram\n .command(\"remove <skill>\")\n .description(\"Remove a skill from the project\")\n .option(\"--delete-files\", \"Delete skill files from disk\")\n .action(async (skillName: string, opts: { deleteFiles?: boolean }) => {\n p.intro(pc.bgCyan(pc.black(\" skilldex remove \")));\n\n const projectRoot = process.cwd();\n const s = p.spinner();\n\n try {\n // Disambiguate name-based input before removing\n let resolvedName = skillName;\n\n if (!skillName.includes(\"/\")) {\n const config = await readConfig(projectRoot);\n const matches = config.skills.filter((sk) => sk.name === skillName);\n\n if (matches.length > 1) {\n const selected = await p.select({\n message: `Multiple skills named \"${skillName}\" indexed. Which one?`,\n options: matches.map((sk) => {\n const agent = getAgentDisplayName(sk.path);\n return { value: sk.path, label: agent ?? sk.path, hint: sk.path };\n }),\n });\n\n if (p.isCancel(selected)) {\n p.cancel(\"Remove cancelled.\");\n process.exit(0);\n }\n\n resolvedName = selected;\n }\n }\n\n let deleteFiles = opts.deleteFiles ?? false;\n\n if (!opts.deleteFiles) {\n const shouldDelete = await p.confirm({\n message: `Delete skill files from disk (${resolvedName})?`,\n initialValue: false,\n });\n\n if (p.isCancel(shouldDelete)) {\n p.cancel(\"Remove cancelled.\");\n process.exit(0);\n }\n\n deleteFiles = shouldDelete;\n }\n\n s.start(\"Removing skill...\");\n const result = await removeSkill(projectRoot, resolvedName, deleteFiles);\n s.stop(\"✓ Skill removed\");\n\n logContextSize(result.managedSize, result.targets);\n const suffix = result.wasDeleted ? \" (files deleted)\" : \" (files kept on disk)\";\n p.outro(pc.green(`Removed \"${result.skillName}\"${suffix}`));\n } catch (error) {\n handleCommandError(error, s);\n }\n });\n\nprogram\n .command(\"list\")\n .description(\"List indexed and available skills\")\n .action(async () => {\n p.intro(pc.bgCyan(pc.black(\" skilldex list \")));\n\n const projectRoot = process.cwd();\n\n try {\n const result = await listSkills(projectRoot);\n\n if (result.indexed.length > 0) {\n p.log.step(pc.bold(\"Indexed skills\"));\n const indexedLines = result.indexed.map(\n (skill) => ` ${pc.green(skill.name)} ${formatSkillPath(skill.path)}`,\n );\n p.log.info(indexedLines.join(\"\\n\"));\n } else {\n p.log.info(pc.dim(\"No indexed skills.\"));\n }\n\n if (result.available.length > 0) {\n p.log.step(pc.bold(\"Available skills (not indexed)\"));\n const availableLines = result.available.map(\n (skill) => ` ${pc.yellow(skill.name)} ${formatSkillPath(skill.path)}`,\n );\n p.log.info(availableLines.join(\"\\n\"));\n }\n\n p.outro(pc.green(\"Done\"));\n } catch (error) {\n handleCommandError(error);\n }\n });\n\nprogram\n .command(\"sync\")\n .description(\"Sync skills and regenerate target file\")\n .action(async () => {\n p.intro(pc.bgCyan(pc.black(\" skilldex sync \")));\n\n const projectRoot = process.cwd();\n const s = p.spinner();\n\n try {\n s.start(\"Syncing...\");\n const result = await syncSkills(projectRoot);\n s.stop(\"✓ Sync complete\");\n\n if (result.removed.length > 0) {\n for (const name of result.removed) {\n p.log.warn(pc.red(`Removed stale skill \"${name}\" (missing from disk)`));\n }\n }\n\n logContextSize(result.managedSize, result.targets);\n\n if (result.changed) {\n p.outro(pc.green(\"Index updated\"));\n } else {\n p.outro(pc.green(\"Everything up to date\"));\n }\n } catch (error) {\n handleCommandError(error, s);\n }\n });\n\nprogram.parse();\n","import { writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { CONFIG_FILENAME, compareByNameThenPath, TARGET_FILE } from \"./constants.js\";\nimport { safeReadFile } from \"./scanner.js\";\nimport type { Config } from \"./types.js\";\n\nfunction getDefaultConfig(): Config {\n return {\n version: 1,\n targets: [TARGET_FILE],\n skills: [],\n };\n}\n\nexport async function readConfig(projectRoot: string): Promise<Config> {\n const configPath = join(projectRoot, CONFIG_FILENAME);\n const content = await safeReadFile(configPath);\n\n if (content === undefined) {\n return getDefaultConfig();\n }\n\n try {\n const parsed = JSON.parse(content) as Config;\n // Validate structure\n if (\n typeof parsed.version !== \"number\" ||\n !Array.isArray(parsed.targets) ||\n !Array.isArray(parsed.skills)\n ) {\n return getDefaultConfig();\n }\n return parsed;\n } catch {\n return getDefaultConfig();\n }\n}\n\nexport async function writeConfig(projectRoot: string, config: Config): Promise<void> {\n const configPath = join(projectRoot, CONFIG_FILENAME);\n const sorted = {\n ...config,\n skills: [...config.skills].sort(compareByNameThenPath),\n };\n const content = JSON.stringify(sorted, null, 2);\n await writeFile(configPath, content, \"utf-8\");\n}\n","export const START_TAG = \"<!-- skilldex:start (auto-generated, do not edit) -->\";\nexport const END_TAG = \"<!-- skilldex:end -->\";\n\nexport const TARGET_FILE = \"AGENTS.md\";\nexport const CONFIG_FILENAME = \"skilldex.config.json\";\nexport const SKILL_META_FILE = \"SKILL.md\";\nexport const SKILLS_DIR_SEGMENTS = [\".agents\", \"skills\"] as const;\nexport const INDEX_HEADER = \"[Skills Index]\";\nexport const INDEX_INSTRUCTION =\n \"IMPORTANT: Prefer retrieval-led reasoning over pre-training-led reasoning for any tasks covered by indexed skills.\";\nexport const CONTEXT_BUDGET_WARN_KB = 20;\nexport const CONTEXT_BUDGET_DANGER_KB = 40;\n\nexport function compareByNameThenPath(\n a: { name: string; path: string },\n b: { name: string; path: string },\n): number {\n return a.name.localeCompare(b.name) || a.path.localeCompare(b.path);\n}\n","import type { Dirent } from \"node:fs\";\nimport { lstat, readdir, readFile } from \"node:fs/promises\";\nimport { join, relative } from \"node:path\";\nimport { getUniqueSkillsDirs } from \"./agents.js\";\nimport { compareByNameThenPath, SKILL_META_FILE } from \"./constants.js\";\nimport type { DiscoveredSkill, SkillFile } from \"./types.js\";\n\n/** Extract key-value pairs from YAML frontmatter (between `---` fences). */\nexport function parseFrontmatter(content: string): Record<string, string> {\n const result: Record<string, string> = {};\n if (!content.startsWith(\"---\")) return result;\n\n const endIndex = content.indexOf(\"\\n---\", 3);\n if (endIndex === -1) return result;\n\n const block = content.slice(4, endIndex);\n for (const line of block.split(\"\\n\")) {\n const colonIndex = line.indexOf(\":\");\n if (colonIndex === -1) continue;\n const key = line.slice(0, colonIndex).trim();\n const value = line.slice(colonIndex + 1).trim();\n if (key) result[key] = value;\n }\n return result;\n}\n\nasync function safeReaddir(dir: string): Promise<Dirent[]> {\n try {\n return await readdir(dir, { withFileTypes: true });\n } catch {\n return [];\n }\n}\n\nexport async function safeReadFile(path: string): Promise<string | undefined> {\n try {\n return await readFile(path, \"utf-8\");\n } catch {\n return undefined;\n }\n}\n\nasync function collectMdFiles(dir: string, skillRoot: string): Promise<SkillFile[]> {\n const entries = await safeReaddir(dir);\n const files: SkillFile[] = [];\n\n for (const entry of entries) {\n const fullPath = join(dir, entry.name);\n if (entry.isDirectory()) {\n const nested = await collectMdFiles(fullPath, skillRoot);\n files.push(...nested);\n } else if (entry.isFile() && entry.name.endsWith(\".md\") && entry.name !== SKILL_META_FILE) {\n files.push({\n relativePath: relative(skillRoot, fullPath),\n name: entry.name.replace(/\\.md$/, \"\"),\n });\n }\n }\n return files;\n}\n\nasync function isSymlink(path: string): Promise<boolean> {\n try {\n const stats = await lstat(path);\n return stats.isSymbolicLink();\n } catch {\n return false;\n }\n}\n\n/** Scan a single skills directory and return discovered skills. */\nasync function scanDirectory(dir: string, projectRoot: string): Promise<DiscoveredSkill[]> {\n const entries = await safeReaddir(dir);\n const skills: DiscoveredSkill[] = [];\n\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n\n const skillPath = join(dir, entry.name);\n\n if (await isSymlink(skillPath)) continue;\n\n let description = \"\";\n const skillMd = await safeReadFile(join(skillPath, SKILL_META_FILE));\n if (skillMd !== undefined) {\n const frontmatter = parseFrontmatter(skillMd);\n description = frontmatter.description ?? \"\";\n }\n\n const files = await collectMdFiles(skillPath, skillPath);\n skills.push({\n name: entry.name,\n description,\n path: skillPath,\n relativePath: relative(projectRoot, skillPath),\n files,\n });\n }\n return skills;\n}\n\n/** Scan all agent source directories for skills. Same-named skills in different directories are all included. */\nexport async function scanForSkills(projectRoot: string): Promise<DiscoveredSkill[]> {\n const results = await Promise.all(\n getUniqueSkillsDirs().map((d) => scanDirectory(join(projectRoot, d), projectRoot)),\n );\n return results.flat().sort(compareByNameThenPath);\n}\n","export interface AgentSource {\n /** Agent identifier, e.g. \"claude-code\" */\n name: string;\n /** Human-readable name, e.g. \"Claude Code\" */\n displayName: string;\n /** Skills directory relative to project root, e.g. \".claude/skills\" */\n skillsDir: string;\n}\n\n/**\n * Known agent source directories (project-scoped).\n * Sourced from the Vercel Skills CLI agent conventions.\n */\nexport const AGENT_SOURCES: AgentSource[] = [\n { name: \"universal\", displayName: \"Universal\", skillsDir: \".agents/skills\" },\n { name: \"antigravity\", displayName: \"Antigravity\", skillsDir: \".agent/skills\" },\n { name: \"claude-code\", displayName: \"Claude Code\", skillsDir: \".claude/skills\" },\n { name: \"codex\", displayName: \"Codex\", skillsDir: \".agents/skills\" },\n { name: \"cursor\", displayName: \"Cursor\", skillsDir: \".cursor/skills\" },\n { name: \"github-copilot\", displayName: \"GitHub Copilot\", skillsDir: \".agents/skills\" },\n { name: \"opencode\", displayName: \"OpenCode\", skillsDir: \".agents/skills\" },\n { name: \"openclaw\", displayName: \"OpenClaw\", skillsDir: \"skills\" },\n { name: \"windsurf\", displayName: \"Windsurf\", skillsDir: \".windsurf/skills\" },\n];\n\n/** Unique skills directories to scan (deduplicates agents sharing the same dir). */\nexport function getUniqueSkillsDirs(): string[] {\n return [...new Set(AGENT_SOURCES.map((a) => a.skillsDir))];\n}\n\n/** Maps a skill's relative path to the first matching agent's display name. */\nexport function getAgentDisplayName(relativePath: string): string | undefined {\n for (const agent of AGENT_SOURCES) {\n if (relativePath.startsWith(`${agent.skillsDir}/`) || relativePath === agent.skillsDir) {\n return agent.displayName;\n }\n }\n return undefined;\n}\n","import { stat, writeFile } from \"node:fs/promises\";\nimport { basename, join } from \"node:path\";\nimport { readConfig } from \"./config.js\";\nimport { END_TAG, START_TAG, TARGET_FILE } from \"./constants.js\";\nimport { generateIndex } from \"./indexer.js\";\nimport { safeReadFile, scanForSkills } from \"./scanner.js\";\nimport type { InitResult, TargetFileInfo } from \"./types.js\";\n\nexport async function getTargetInfos(\n projectRoot: string,\n targets: string[],\n): Promise<TargetFileInfo[]> {\n return Promise.all(\n targets.map(async (t) => {\n const p = join(projectRoot, t);\n const s = await stat(p);\n return { file: basename(t), path: p, totalSize: s.size };\n }),\n );\n}\n\nexport function buildManagedSection(indexContent: string): string {\n return `${START_TAG}\\n${indexContent}\\n${END_TAG}`;\n}\n\n/** Write or update the managed skilldex section in a target file. Creates, appends, or replaces as needed. Returns the written file content. */\nexport async function writeTargetFile(\n projectRoot: string,\n indexContent: string,\n targetFile: string = TARGET_FILE,\n): Promise<string> {\n const targetPath = join(projectRoot, targetFile);\n const section = buildManagedSection(indexContent);\n\n const existing = await safeReadFile(targetPath);\n\n let output: string;\n if (existing === undefined) {\n output = `${section}\\n`;\n } else if (existing.includes(START_TAG) && existing.includes(END_TAG)) {\n const startIdx = existing.indexOf(START_TAG);\n const endIdx = existing.indexOf(END_TAG) + END_TAG.length;\n output = existing.slice(0, startIdx) + section + existing.slice(endIdx);\n } else {\n output = `${existing.trimEnd()}\\n\\n${section}\\n`;\n }\n\n await writeFile(targetPath, output, \"utf-8\");\n return output;\n}\n\nexport interface RegenerateResult extends InitResult {\n /** Map of target file path → written content */\n writtenContent: Map<string, string>;\n}\n\n/** Regenerate all target files from config (reads config, scans indexed skills, writes targets). */\nexport async function regenerateFromConfig(projectRoot: string): Promise<RegenerateResult> {\n const config = await readConfig(projectRoot);\n const allSkills = await scanForSkills(projectRoot);\n\n // Map skill paths from config to DiscoveredSkill objects\n const skillMap = new Map(allSkills.map((s) => [s.relativePath, s]));\n const skills = config.skills\n .map((entry) => skillMap.get(entry.path))\n .filter((s) => s !== undefined);\n\n const index = generateIndex(skills);\n\n const writtenContent = new Map<string, string>();\n for (const target of config.targets) {\n const content = await writeTargetFile(projectRoot, index, target);\n writtenContent.set(join(projectRoot, target), content);\n }\n\n const managedSize = Buffer.byteLength(buildManagedSection(index));\n const targets = await getTargetInfos(projectRoot, config.targets);\n\n return {\n skillCount: skills.length,\n managedSize,\n targets,\n writtenContent,\n };\n}\n","import { dirname } from \"node:path\";\nimport { INDEX_HEADER, INDEX_INSTRUCTION } from \"./constants.js\";\nimport type { DiscoveredSkill } from \"./types.js\";\n\nfunction groupFilesBySubdir(\n files: { relativePath: string; name: string }[],\n): Map<string, string[]> {\n const groups = new Map<string, string[]>();\n for (const file of files) {\n const dir = dirname(file.relativePath);\n const key = dir === \".\" ? \"\" : dir;\n const existing = groups.get(key);\n if (existing) {\n existing.push(`${file.name}.md`);\n } else {\n groups.set(key, [`${file.name}.md`]);\n }\n }\n return groups;\n}\n\nexport function generateIndex(skills: DiscoveredSkill[]): string {\n const segments: string[] = [INDEX_HEADER, INDEX_INSTRUCTION];\n\n for (const skill of skills) {\n segments.push(`[${skill.name}]`);\n segments.push(`root:./${skill.relativePath}`);\n\n if (skill.description) {\n segments.push(`desc:${skill.description}`);\n }\n\n const groups = groupFilesBySubdir(skill.files);\n for (const [subdir, fileNames] of groups) {\n const fileList = `{${fileNames.join(\",\")}}`;\n if (subdir) {\n segments.push(`${subdir}:${fileList}`);\n } else {\n segments.push(fileList);\n }\n }\n }\n\n return segments.join(\"|\");\n}\n","import { readConfig, writeConfig } from \"./config.js\";\nimport { scanForSkills } from \"./scanner.js\";\nimport type { AddResult, DiscoveredSkill } from \"./types.js\";\nimport { regenerateFromConfig } from \"./writer.js\";\n\nexport async function addSkill(projectRoot: string, skillName: string): Promise<AddResult> {\n const config = await readConfig(projectRoot);\n const allSkills = await scanForSkills(projectRoot);\n\n const isPath = skillName.includes(\"/\");\n\n let targetSkill: DiscoveredSkill | undefined;\n\n if (isPath) {\n // Path-based lookup for disambiguation\n targetSkill = allSkills.find((s) => s.relativePath === skillName);\n if (!targetSkill) {\n throw new Error(`Skill \"${skillName}\" not found. Did you create the skill directory?`);\n }\n } else {\n // Name-based lookup\n const matches = allSkills.filter((s) => s.name === skillName);\n if (matches.length === 0) {\n throw new Error(`Skill \"${skillName}\" not found. Did you create the skill directory?`);\n }\n if (matches.length > 1) {\n const paths = matches.map((s) => ` ${s.relativePath}`).join(\"\\n\");\n throw new Error(`Multiple skills named \"${skillName}\" found. Specify the path:\\n${paths}`);\n }\n targetSkill = matches[0];\n }\n\n if (config.skills.some((s) => s.path === targetSkill.relativePath)) {\n throw new Error(`Skill \"${targetSkill.relativePath}\" is already indexed`);\n }\n\n config.skills.push({\n name: targetSkill.name,\n path: targetSkill.relativePath,\n });\n\n await writeConfig(projectRoot, config);\n\n const result = await regenerateFromConfig(projectRoot);\n\n return {\n skillName: targetSkill.name,\n managedSize: result.managedSize,\n targets: result.targets,\n };\n}\n","import { writeConfig } from \"./config.js\";\nimport { TARGET_FILE } from \"./constants.js\";\nimport { scanForSkills } from \"./scanner.js\";\nimport type { DiscoveredSkill, InitResult } from \"./types.js\";\nimport { regenerateFromConfig } from \"./writer.js\";\n\n/** Scan for skills, filter by selection, and write the index to target files. */\nexport async function init(options: {\n projectRoot: string;\n selectedSkills?: string[];\n yes?: boolean;\n}): Promise<InitResult> {\n const { projectRoot, selectedSkills } = options;\n\n const discovered = await scanForSkills(projectRoot);\n\n let skills: DiscoveredSkill[];\n if (selectedSkills) {\n const selected = new Set(selectedSkills);\n skills = discovered.filter((s) => selected.has(s.name) || selected.has(s.relativePath));\n } else {\n skills = discovered;\n }\n\n return initWithSkills(projectRoot, skills);\n}\n\n/** Index a specific set of skills and write to target file(s). */\nexport async function initWithSkills(\n projectRoot: string,\n skills: DiscoveredSkill[],\n targets: string[] = [TARGET_FILE],\n): Promise<InitResult> {\n const config = {\n version: 1 as const,\n targets,\n skills: skills.map((skill) => ({\n name: skill.name,\n path: skill.relativePath,\n })),\n };\n await writeConfig(projectRoot, config);\n\n return regenerateFromConfig(projectRoot);\n}\n","import { readConfig } from \"./config.js\";\nimport { scanForSkills } from \"./scanner.js\";\nimport type { ListResult, SkillInfo } from \"./types.js\";\n\nexport async function listSkills(projectRoot: string): Promise<ListResult> {\n const config = await readConfig(projectRoot);\n const allSkills = await scanForSkills(projectRoot);\n\n const indexedPaths = new Set(config.skills.map((s) => s.path));\n const skillMap = new Map(allSkills.map((s) => [s.relativePath, s]));\n\n const indexed: SkillInfo[] = config.skills\n .map((entry) => {\n const discovered = skillMap.get(entry.path);\n if (!discovered) return undefined;\n return {\n name: entry.name,\n path: entry.path,\n description: discovered.description,\n };\n })\n .filter((s) => s !== undefined);\n\n const available: SkillInfo[] = allSkills\n .filter((s) => !indexedPaths.has(s.relativePath))\n .map((s) => ({\n name: s.name,\n description: s.description,\n path: s.relativePath,\n }));\n\n return { indexed, available };\n}\n","import { rm } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { readConfig, writeConfig } from \"./config.js\";\nimport type { RemoveResult } from \"./types.js\";\nimport { regenerateFromConfig } from \"./writer.js\";\n\nexport async function removeSkill(\n projectRoot: string,\n skillName: string,\n deleteFiles = false,\n): Promise<RemoveResult> {\n const config = await readConfig(projectRoot);\n\n const isPath = skillName.includes(\"/\");\n\n let skillIndex: number;\n\n if (isPath) {\n skillIndex = config.skills.findIndex((s) => s.path === skillName);\n if (skillIndex === -1) {\n throw new Error(`Skill \"${skillName}\" is not indexed`);\n }\n } else {\n const matches = config.skills\n .map((s, i) => ({ entry: s, index: i }))\n .filter(({ entry }) => entry.name === skillName);\n\n if (matches.length === 0) {\n throw new Error(`Skill \"${skillName}\" is not indexed`);\n }\n if (matches.length > 1) {\n const paths = matches.map(({ entry }) => ` ${entry.path}`).join(\"\\n\");\n throw new Error(`Multiple skills named \"${skillName}\" indexed. Specify the path:\\n${paths}`);\n }\n skillIndex = matches[0].index;\n }\n\n const entry = config.skills[skillIndex];\n const skillPath = join(projectRoot, entry.path);\n\n config.skills.splice(skillIndex, 1);\n await writeConfig(projectRoot, config);\n\n if (deleteFiles) {\n await rm(skillPath, { recursive: true, force: true });\n }\n\n const result = await regenerateFromConfig(projectRoot);\n\n return {\n skillName: entry.name,\n wasDeleted: deleteFiles,\n managedSize: result.managedSize,\n targets: result.targets,\n };\n}\n","import { join } from \"node:path\";\nimport { readConfig, writeConfig } from \"./config.js\";\nimport { safeReadFile, scanForSkills } from \"./scanner.js\";\nimport type { SyncResult } from \"./types.js\";\nimport { regenerateFromConfig } from \"./writer.js\";\n\nexport async function syncSkills(projectRoot: string): Promise<SyncResult> {\n const config = await readConfig(projectRoot);\n const onDisk = await scanForSkills(projectRoot);\n const diskPaths = new Set(onDisk.map((s) => s.relativePath));\n\n // Find stale entries: in config but not on disk\n const stale = config.skills.filter((s) => !diskPaths.has(s.path));\n const removed = stale.map((s) => s.name);\n\n if (stale.length > 0) {\n const stalePaths = new Set(stale.map((s) => s.path));\n config.skills = config.skills.filter((s) => !stalePaths.has(s.path));\n await writeConfig(projectRoot, config);\n }\n\n const targetPaths = config.targets.map((t) => join(projectRoot, t));\n\n // Read before-state for all targets\n const beforeMap = new Map<string, string | undefined>();\n for (const targetPath of targetPaths) {\n beforeMap.set(targetPath, await safeReadFile(targetPath));\n }\n\n // Nothing to do if no skills indexed and no target files exist\n if (config.skills.length === 0 && [...beforeMap.values()].every((v) => v === undefined)) {\n return { removed, changed: false, managedSize: 0, targets: [] };\n }\n\n const result = await regenerateFromConfig(projectRoot);\n\n // Check if ANY target changed using the written content from regeneration\n let changed = false;\n for (const targetPath of targetPaths) {\n const after = result.writtenContent.get(targetPath);\n if (beforeMap.get(targetPath) !== after) {\n changed = true;\n break;\n }\n }\n\n return {\n removed,\n changed,\n managedSize: result.managedSize,\n targets: result.targets,\n };\n}\n","import * as p from \"@clack/prompts\";\nimport pc from \"picocolors\";\nimport { getAgentDisplayName } from \"../lib/agents.js\";\nimport { CONTEXT_BUDGET_DANGER_KB, CONTEXT_BUDGET_WARN_KB } from \"../lib/constants.js\";\nimport type { TargetFileInfo } from \"../lib/types.js\";\n\nexport function pluralize(count: number, singular: string, plural: string): string {\n return count === 1 ? singular : plural;\n}\n\nfunction formatKb(bytes: number): string {\n return `${(bytes / 1024).toFixed(1)} KB`;\n}\n\nexport function logContextSize(managedSize: number, targets: TargetFileInfo[]): void {\n const sizeKb = managedSize / 1024;\n const sizeFormatted = formatKb(managedSize);\n let sizeLabel: string;\n if (sizeKb < CONTEXT_BUDGET_WARN_KB) {\n sizeLabel = pc.green(sizeFormatted);\n } else if (sizeKb < CONTEXT_BUDGET_DANGER_KB) {\n sizeLabel = pc.yellow(sizeFormatted);\n } else {\n sizeLabel = pc.red(`${sizeFormatted} — may degrade agent performance`);\n }\n\n const targetLines = targets.map(\n (t) => ` ${t.file} ${pc.dim(`${formatKb(t.totalSize)} total`)}`,\n );\n p.log.info(`Context: ${sizeLabel} (managed section)\\n${targetLines.join(\"\\n\")}`);\n}\n\nexport function formatSkillPath(relativePath: string): string {\n const agent = getAgentDisplayName(relativePath);\n if (agent) return `${pc.cyan(agent)} ${pc.dim(relativePath)}`;\n return pc.dim(relativePath);\n}\n\nexport function handleCommandError(error: unknown, spinner?: ReturnType<typeof p.spinner>): never {\n if (spinner) {\n spinner.stop(\"✗ Failed\");\n }\n const message = error instanceof Error ? error.message : String(error);\n p.outro(pc.red(message));\n process.exit(1);\n}\n"],"mappings":"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","names":["p","pc","join","join","writeFile","join","p","join","writeFile","join","entry","join","join","join","spinner","pc"]}
package/dist/index.cjs ADDED
@@ -0,0 +1,510 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ AGENT_SOURCES: () => AGENT_SOURCES,
24
+ CONFIG_FILENAME: () => CONFIG_FILENAME,
25
+ CONTEXT_BUDGET_DANGER_KB: () => CONTEXT_BUDGET_DANGER_KB,
26
+ CONTEXT_BUDGET_WARN_KB: () => CONTEXT_BUDGET_WARN_KB,
27
+ END_TAG: () => END_TAG,
28
+ INDEX_HEADER: () => INDEX_HEADER,
29
+ INDEX_INSTRUCTION: () => INDEX_INSTRUCTION,
30
+ SKILL_META_FILE: () => SKILL_META_FILE,
31
+ START_TAG: () => START_TAG,
32
+ TARGET_FILE: () => TARGET_FILE,
33
+ addSkill: () => addSkill,
34
+ buildManagedSection: () => buildManagedSection,
35
+ compareByNameThenPath: () => compareByNameThenPath,
36
+ generateIndex: () => generateIndex,
37
+ getAgentDisplayName: () => getAgentDisplayName,
38
+ getUniqueSkillsDirs: () => getUniqueSkillsDirs,
39
+ init: () => init,
40
+ initWithSkills: () => initWithSkills,
41
+ listSkills: () => listSkills,
42
+ readConfig: () => readConfig,
43
+ regenerateFromConfig: () => regenerateFromConfig,
44
+ removeSkill: () => removeSkill,
45
+ scanForSkills: () => scanForSkills,
46
+ syncSkills: () => syncSkills,
47
+ writeConfig: () => writeConfig,
48
+ writeTargetFile: () => writeTargetFile
49
+ });
50
+ module.exports = __toCommonJS(index_exports);
51
+
52
+ // src/lib/config.ts
53
+ var import_promises2 = require("fs/promises");
54
+ var import_node_path2 = require("path");
55
+
56
+ // src/lib/constants.ts
57
+ var START_TAG = "<!-- skilldex:start (auto-generated, do not edit) -->";
58
+ var END_TAG = "<!-- skilldex:end -->";
59
+ var TARGET_FILE = "AGENTS.md";
60
+ var CONFIG_FILENAME = "skilldex.config.json";
61
+ var SKILL_META_FILE = "SKILL.md";
62
+ var INDEX_HEADER = "[Skills Index]";
63
+ var INDEX_INSTRUCTION = "IMPORTANT: Prefer retrieval-led reasoning over pre-training-led reasoning for any tasks covered by indexed skills.";
64
+ var CONTEXT_BUDGET_WARN_KB = 20;
65
+ var CONTEXT_BUDGET_DANGER_KB = 40;
66
+ function compareByNameThenPath(a, b) {
67
+ return a.name.localeCompare(b.name) || a.path.localeCompare(b.path);
68
+ }
69
+
70
+ // src/lib/scanner.ts
71
+ var import_promises = require("fs/promises");
72
+ var import_node_path = require("path");
73
+
74
+ // src/lib/agents.ts
75
+ var AGENT_SOURCES = [
76
+ { name: "universal", displayName: "Universal", skillsDir: ".agents/skills" },
77
+ { name: "antigravity", displayName: "Antigravity", skillsDir: ".agent/skills" },
78
+ { name: "claude-code", displayName: "Claude Code", skillsDir: ".claude/skills" },
79
+ { name: "codex", displayName: "Codex", skillsDir: ".agents/skills" },
80
+ { name: "cursor", displayName: "Cursor", skillsDir: ".cursor/skills" },
81
+ { name: "github-copilot", displayName: "GitHub Copilot", skillsDir: ".agents/skills" },
82
+ { name: "opencode", displayName: "OpenCode", skillsDir: ".agents/skills" },
83
+ { name: "openclaw", displayName: "OpenClaw", skillsDir: "skills" },
84
+ { name: "windsurf", displayName: "Windsurf", skillsDir: ".windsurf/skills" }
85
+ ];
86
+ function getUniqueSkillsDirs() {
87
+ return [...new Set(AGENT_SOURCES.map((a) => a.skillsDir))];
88
+ }
89
+ function getAgentDisplayName(relativePath) {
90
+ for (const agent of AGENT_SOURCES) {
91
+ if (relativePath.startsWith(`${agent.skillsDir}/`) || relativePath === agent.skillsDir) {
92
+ return agent.displayName;
93
+ }
94
+ }
95
+ return void 0;
96
+ }
97
+
98
+ // src/lib/scanner.ts
99
+ function parseFrontmatter(content) {
100
+ const result = {};
101
+ if (!content.startsWith("---")) return result;
102
+ const endIndex = content.indexOf("\n---", 3);
103
+ if (endIndex === -1) return result;
104
+ const block = content.slice(4, endIndex);
105
+ for (const line of block.split("\n")) {
106
+ const colonIndex = line.indexOf(":");
107
+ if (colonIndex === -1) continue;
108
+ const key = line.slice(0, colonIndex).trim();
109
+ const value = line.slice(colonIndex + 1).trim();
110
+ if (key) result[key] = value;
111
+ }
112
+ return result;
113
+ }
114
+ async function safeReaddir(dir) {
115
+ try {
116
+ return await (0, import_promises.readdir)(dir, { withFileTypes: true });
117
+ } catch {
118
+ return [];
119
+ }
120
+ }
121
+ async function safeReadFile(path) {
122
+ try {
123
+ return await (0, import_promises.readFile)(path, "utf-8");
124
+ } catch {
125
+ return void 0;
126
+ }
127
+ }
128
+ async function collectMdFiles(dir, skillRoot) {
129
+ const entries = await safeReaddir(dir);
130
+ const files = [];
131
+ for (const entry of entries) {
132
+ const fullPath = (0, import_node_path.join)(dir, entry.name);
133
+ if (entry.isDirectory()) {
134
+ const nested = await collectMdFiles(fullPath, skillRoot);
135
+ files.push(...nested);
136
+ } else if (entry.isFile() && entry.name.endsWith(".md") && entry.name !== SKILL_META_FILE) {
137
+ files.push({
138
+ relativePath: (0, import_node_path.relative)(skillRoot, fullPath),
139
+ name: entry.name.replace(/\.md$/, "")
140
+ });
141
+ }
142
+ }
143
+ return files;
144
+ }
145
+ async function isSymlink(path) {
146
+ try {
147
+ const stats = await (0, import_promises.lstat)(path);
148
+ return stats.isSymbolicLink();
149
+ } catch {
150
+ return false;
151
+ }
152
+ }
153
+ async function scanDirectory(dir, projectRoot) {
154
+ const entries = await safeReaddir(dir);
155
+ const skills = [];
156
+ for (const entry of entries) {
157
+ if (!entry.isDirectory()) continue;
158
+ const skillPath = (0, import_node_path.join)(dir, entry.name);
159
+ if (await isSymlink(skillPath)) continue;
160
+ let description = "";
161
+ const skillMd = await safeReadFile((0, import_node_path.join)(skillPath, SKILL_META_FILE));
162
+ if (skillMd !== void 0) {
163
+ const frontmatter = parseFrontmatter(skillMd);
164
+ description = frontmatter.description ?? "";
165
+ }
166
+ const files = await collectMdFiles(skillPath, skillPath);
167
+ skills.push({
168
+ name: entry.name,
169
+ description,
170
+ path: skillPath,
171
+ relativePath: (0, import_node_path.relative)(projectRoot, skillPath),
172
+ files
173
+ });
174
+ }
175
+ return skills;
176
+ }
177
+ async function scanForSkills(projectRoot) {
178
+ const results = await Promise.all(
179
+ getUniqueSkillsDirs().map((d) => scanDirectory((0, import_node_path.join)(projectRoot, d), projectRoot))
180
+ );
181
+ return results.flat().sort(compareByNameThenPath);
182
+ }
183
+
184
+ // src/lib/config.ts
185
+ function getDefaultConfig() {
186
+ return {
187
+ version: 1,
188
+ targets: [TARGET_FILE],
189
+ skills: []
190
+ };
191
+ }
192
+ async function readConfig(projectRoot) {
193
+ const configPath = (0, import_node_path2.join)(projectRoot, CONFIG_FILENAME);
194
+ const content = await safeReadFile(configPath);
195
+ if (content === void 0) {
196
+ return getDefaultConfig();
197
+ }
198
+ try {
199
+ const parsed = JSON.parse(content);
200
+ if (typeof parsed.version !== "number" || !Array.isArray(parsed.targets) || !Array.isArray(parsed.skills)) {
201
+ return getDefaultConfig();
202
+ }
203
+ return parsed;
204
+ } catch {
205
+ return getDefaultConfig();
206
+ }
207
+ }
208
+ async function writeConfig(projectRoot, config) {
209
+ const configPath = (0, import_node_path2.join)(projectRoot, CONFIG_FILENAME);
210
+ const sorted = {
211
+ ...config,
212
+ skills: [...config.skills].sort(compareByNameThenPath)
213
+ };
214
+ const content = JSON.stringify(sorted, null, 2);
215
+ await (0, import_promises2.writeFile)(configPath, content, "utf-8");
216
+ }
217
+
218
+ // src/lib/writer.ts
219
+ var import_promises3 = require("fs/promises");
220
+ var import_node_path4 = require("path");
221
+
222
+ // src/lib/indexer.ts
223
+ var import_node_path3 = require("path");
224
+ function groupFilesBySubdir(files) {
225
+ const groups = /* @__PURE__ */ new Map();
226
+ for (const file of files) {
227
+ const dir = (0, import_node_path3.dirname)(file.relativePath);
228
+ const key = dir === "." ? "" : dir;
229
+ const existing = groups.get(key);
230
+ if (existing) {
231
+ existing.push(`${file.name}.md`);
232
+ } else {
233
+ groups.set(key, [`${file.name}.md`]);
234
+ }
235
+ }
236
+ return groups;
237
+ }
238
+ function generateIndex(skills) {
239
+ const segments = [INDEX_HEADER, INDEX_INSTRUCTION];
240
+ for (const skill of skills) {
241
+ segments.push(`[${skill.name}]`);
242
+ segments.push(`root:./${skill.relativePath}`);
243
+ if (skill.description) {
244
+ segments.push(`desc:${skill.description}`);
245
+ }
246
+ const groups = groupFilesBySubdir(skill.files);
247
+ for (const [subdir, fileNames] of groups) {
248
+ const fileList = `{${fileNames.join(",")}}`;
249
+ if (subdir) {
250
+ segments.push(`${subdir}:${fileList}`);
251
+ } else {
252
+ segments.push(fileList);
253
+ }
254
+ }
255
+ }
256
+ return segments.join("|");
257
+ }
258
+
259
+ // src/lib/writer.ts
260
+ async function getTargetInfos(projectRoot, targets) {
261
+ return Promise.all(
262
+ targets.map(async (t) => {
263
+ const p = (0, import_node_path4.join)(projectRoot, t);
264
+ const s = await (0, import_promises3.stat)(p);
265
+ return { file: (0, import_node_path4.basename)(t), path: p, totalSize: s.size };
266
+ })
267
+ );
268
+ }
269
+ function buildManagedSection(indexContent) {
270
+ return `${START_TAG}
271
+ ${indexContent}
272
+ ${END_TAG}`;
273
+ }
274
+ async function writeTargetFile(projectRoot, indexContent, targetFile = TARGET_FILE) {
275
+ const targetPath = (0, import_node_path4.join)(projectRoot, targetFile);
276
+ const section = buildManagedSection(indexContent);
277
+ const existing = await safeReadFile(targetPath);
278
+ let output;
279
+ if (existing === void 0) {
280
+ output = `${section}
281
+ `;
282
+ } else if (existing.includes(START_TAG) && existing.includes(END_TAG)) {
283
+ const startIdx = existing.indexOf(START_TAG);
284
+ const endIdx = existing.indexOf(END_TAG) + END_TAG.length;
285
+ output = existing.slice(0, startIdx) + section + existing.slice(endIdx);
286
+ } else {
287
+ output = `${existing.trimEnd()}
288
+
289
+ ${section}
290
+ `;
291
+ }
292
+ await (0, import_promises3.writeFile)(targetPath, output, "utf-8");
293
+ return output;
294
+ }
295
+ async function regenerateFromConfig(projectRoot) {
296
+ const config = await readConfig(projectRoot);
297
+ const allSkills = await scanForSkills(projectRoot);
298
+ const skillMap = new Map(allSkills.map((s) => [s.relativePath, s]));
299
+ const skills = config.skills.map((entry) => skillMap.get(entry.path)).filter((s) => s !== void 0);
300
+ const index = generateIndex(skills);
301
+ const writtenContent = /* @__PURE__ */ new Map();
302
+ for (const target of config.targets) {
303
+ const content = await writeTargetFile(projectRoot, index, target);
304
+ writtenContent.set((0, import_node_path4.join)(projectRoot, target), content);
305
+ }
306
+ const managedSize = Buffer.byteLength(buildManagedSection(index));
307
+ const targets = await getTargetInfos(projectRoot, config.targets);
308
+ return {
309
+ skillCount: skills.length,
310
+ managedSize,
311
+ targets,
312
+ writtenContent
313
+ };
314
+ }
315
+
316
+ // src/lib/add.ts
317
+ async function addSkill(projectRoot, skillName) {
318
+ const config = await readConfig(projectRoot);
319
+ const allSkills = await scanForSkills(projectRoot);
320
+ const isPath = skillName.includes("/");
321
+ let targetSkill;
322
+ if (isPath) {
323
+ targetSkill = allSkills.find((s) => s.relativePath === skillName);
324
+ if (!targetSkill) {
325
+ throw new Error(`Skill "${skillName}" not found. Did you create the skill directory?`);
326
+ }
327
+ } else {
328
+ const matches = allSkills.filter((s) => s.name === skillName);
329
+ if (matches.length === 0) {
330
+ throw new Error(`Skill "${skillName}" not found. Did you create the skill directory?`);
331
+ }
332
+ if (matches.length > 1) {
333
+ const paths = matches.map((s) => ` ${s.relativePath}`).join("\n");
334
+ throw new Error(`Multiple skills named "${skillName}" found. Specify the path:
335
+ ${paths}`);
336
+ }
337
+ targetSkill = matches[0];
338
+ }
339
+ if (config.skills.some((s) => s.path === targetSkill.relativePath)) {
340
+ throw new Error(`Skill "${targetSkill.relativePath}" is already indexed`);
341
+ }
342
+ config.skills.push({
343
+ name: targetSkill.name,
344
+ path: targetSkill.relativePath
345
+ });
346
+ await writeConfig(projectRoot, config);
347
+ const result = await regenerateFromConfig(projectRoot);
348
+ return {
349
+ skillName: targetSkill.name,
350
+ managedSize: result.managedSize,
351
+ targets: result.targets
352
+ };
353
+ }
354
+
355
+ // src/lib/init.ts
356
+ async function init(options) {
357
+ const { projectRoot, selectedSkills } = options;
358
+ const discovered = await scanForSkills(projectRoot);
359
+ let skills;
360
+ if (selectedSkills) {
361
+ const selected = new Set(selectedSkills);
362
+ skills = discovered.filter((s) => selected.has(s.name) || selected.has(s.relativePath));
363
+ } else {
364
+ skills = discovered;
365
+ }
366
+ return initWithSkills(projectRoot, skills);
367
+ }
368
+ async function initWithSkills(projectRoot, skills, targets = [TARGET_FILE]) {
369
+ const config = {
370
+ version: 1,
371
+ targets,
372
+ skills: skills.map((skill) => ({
373
+ name: skill.name,
374
+ path: skill.relativePath
375
+ }))
376
+ };
377
+ await writeConfig(projectRoot, config);
378
+ return regenerateFromConfig(projectRoot);
379
+ }
380
+
381
+ // src/lib/list.ts
382
+ async function listSkills(projectRoot) {
383
+ const config = await readConfig(projectRoot);
384
+ const allSkills = await scanForSkills(projectRoot);
385
+ const indexedPaths = new Set(config.skills.map((s) => s.path));
386
+ const skillMap = new Map(allSkills.map((s) => [s.relativePath, s]));
387
+ const indexed = config.skills.map((entry) => {
388
+ const discovered = skillMap.get(entry.path);
389
+ if (!discovered) return void 0;
390
+ return {
391
+ name: entry.name,
392
+ path: entry.path,
393
+ description: discovered.description
394
+ };
395
+ }).filter((s) => s !== void 0);
396
+ const available = allSkills.filter((s) => !indexedPaths.has(s.relativePath)).map((s) => ({
397
+ name: s.name,
398
+ description: s.description,
399
+ path: s.relativePath
400
+ }));
401
+ return { indexed, available };
402
+ }
403
+
404
+ // src/lib/remove.ts
405
+ var import_promises4 = require("fs/promises");
406
+ var import_node_path5 = require("path");
407
+ async function removeSkill(projectRoot, skillName, deleteFiles = false) {
408
+ const config = await readConfig(projectRoot);
409
+ const isPath = skillName.includes("/");
410
+ let skillIndex;
411
+ if (isPath) {
412
+ skillIndex = config.skills.findIndex((s) => s.path === skillName);
413
+ if (skillIndex === -1) {
414
+ throw new Error(`Skill "${skillName}" is not indexed`);
415
+ }
416
+ } else {
417
+ const matches = config.skills.map((s, i) => ({ entry: s, index: i })).filter(({ entry: entry2 }) => entry2.name === skillName);
418
+ if (matches.length === 0) {
419
+ throw new Error(`Skill "${skillName}" is not indexed`);
420
+ }
421
+ if (matches.length > 1) {
422
+ const paths = matches.map(({ entry: entry2 }) => ` ${entry2.path}`).join("\n");
423
+ throw new Error(`Multiple skills named "${skillName}" indexed. Specify the path:
424
+ ${paths}`);
425
+ }
426
+ skillIndex = matches[0].index;
427
+ }
428
+ const entry = config.skills[skillIndex];
429
+ const skillPath = (0, import_node_path5.join)(projectRoot, entry.path);
430
+ config.skills.splice(skillIndex, 1);
431
+ await writeConfig(projectRoot, config);
432
+ if (deleteFiles) {
433
+ await (0, import_promises4.rm)(skillPath, { recursive: true, force: true });
434
+ }
435
+ const result = await regenerateFromConfig(projectRoot);
436
+ return {
437
+ skillName: entry.name,
438
+ wasDeleted: deleteFiles,
439
+ managedSize: result.managedSize,
440
+ targets: result.targets
441
+ };
442
+ }
443
+
444
+ // src/lib/sync.ts
445
+ var import_node_path6 = require("path");
446
+ async function syncSkills(projectRoot) {
447
+ const config = await readConfig(projectRoot);
448
+ const onDisk = await scanForSkills(projectRoot);
449
+ const diskPaths = new Set(onDisk.map((s) => s.relativePath));
450
+ const stale = config.skills.filter((s) => !diskPaths.has(s.path));
451
+ const removed = stale.map((s) => s.name);
452
+ if (stale.length > 0) {
453
+ const stalePaths = new Set(stale.map((s) => s.path));
454
+ config.skills = config.skills.filter((s) => !stalePaths.has(s.path));
455
+ await writeConfig(projectRoot, config);
456
+ }
457
+ const targetPaths = config.targets.map((t) => (0, import_node_path6.join)(projectRoot, t));
458
+ const beforeMap = /* @__PURE__ */ new Map();
459
+ for (const targetPath of targetPaths) {
460
+ beforeMap.set(targetPath, await safeReadFile(targetPath));
461
+ }
462
+ if (config.skills.length === 0 && [...beforeMap.values()].every((v) => v === void 0)) {
463
+ return { removed, changed: false, managedSize: 0, targets: [] };
464
+ }
465
+ const result = await regenerateFromConfig(projectRoot);
466
+ let changed = false;
467
+ for (const targetPath of targetPaths) {
468
+ const after = result.writtenContent.get(targetPath);
469
+ if (beforeMap.get(targetPath) !== after) {
470
+ changed = true;
471
+ break;
472
+ }
473
+ }
474
+ return {
475
+ removed,
476
+ changed,
477
+ managedSize: result.managedSize,
478
+ targets: result.targets
479
+ };
480
+ }
481
+ // Annotate the CommonJS export names for ESM import in node:
482
+ 0 && (module.exports = {
483
+ AGENT_SOURCES,
484
+ CONFIG_FILENAME,
485
+ CONTEXT_BUDGET_DANGER_KB,
486
+ CONTEXT_BUDGET_WARN_KB,
487
+ END_TAG,
488
+ INDEX_HEADER,
489
+ INDEX_INSTRUCTION,
490
+ SKILL_META_FILE,
491
+ START_TAG,
492
+ TARGET_FILE,
493
+ addSkill,
494
+ buildManagedSection,
495
+ compareByNameThenPath,
496
+ generateIndex,
497
+ getAgentDisplayName,
498
+ getUniqueSkillsDirs,
499
+ init,
500
+ initWithSkills,
501
+ listSkills,
502
+ readConfig,
503
+ regenerateFromConfig,
504
+ removeSkill,
505
+ scanForSkills,
506
+ syncSkills,
507
+ writeConfig,
508
+ writeTargetFile
509
+ });
510
+ //# sourceMappingURL=index.cjs.map