@claude-collective/cli 0.2.0 → 0.6.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.
- package/CHANGELOG.md +113 -0
- package/README.md +1 -1
- package/dist/chunk-367K3JB3.js +84 -0
- package/dist/chunk-367K3JB3.js.map +1 -0
- package/dist/chunk-6ESUJMM7.js +54 -0
- package/dist/chunk-6ESUJMM7.js.map +1 -0
- package/dist/chunk-6OY6ZYQF.js +93 -0
- package/dist/chunk-6OY6ZYQF.js.map +1 -0
- package/dist/chunk-6WEQADPL.js +307 -0
- package/dist/chunk-6WEQADPL.js.map +1 -0
- package/dist/chunk-AU7XVCLO.js +91 -0
- package/dist/chunk-AU7XVCLO.js.map +1 -0
- package/dist/chunk-AZP2AA5M.js +425 -0
- package/dist/chunk-AZP2AA5M.js.map +1 -0
- package/dist/chunk-D4IQAT27.js +114 -0
- package/dist/chunk-D4IQAT27.js.map +1 -0
- package/dist/chunk-DHET7RCE.js +50 -0
- package/dist/chunk-DHET7RCE.js.map +1 -0
- package/dist/chunk-DHFFRMF6.js +31 -0
- package/dist/chunk-DHFFRMF6.js.map +1 -0
- package/dist/chunk-FKU7VSUD.js +453 -0
- package/dist/chunk-FKU7VSUD.js.map +1 -0
- package/dist/chunk-J2Y4A3LP.js +478 -0
- package/dist/chunk-J2Y4A3LP.js.map +1 -0
- package/dist/chunk-JMQGWQZU.js +607 -0
- package/dist/chunk-JMQGWQZU.js.map +1 -0
- package/dist/chunk-JY4RO76L.js +73 -0
- package/dist/chunk-JY4RO76L.js.map +1 -0
- package/dist/chunk-M7YCPFIX.js +108 -0
- package/dist/chunk-M7YCPFIX.js.map +1 -0
- package/dist/chunk-MJSFR562.js +57 -0
- package/dist/chunk-MJSFR562.js.map +1 -0
- package/dist/chunk-MMDXNZPF.js +69 -0
- package/dist/chunk-MMDXNZPF.js.map +1 -0
- package/dist/chunk-MYAVQ23U.js +356 -0
- package/dist/chunk-MYAVQ23U.js.map +1 -0
- package/dist/chunk-OSQDDJXX.js +146 -0
- package/dist/chunk-OSQDDJXX.js.map +1 -0
- package/dist/chunk-QESUUPOE.js +241 -0
- package/dist/chunk-QESUUPOE.js.map +1 -0
- package/dist/chunk-SJYG4EJZ.js +57 -0
- package/dist/chunk-SJYG4EJZ.js.map +1 -0
- package/dist/chunk-SYQ7R2JO.js +95 -0
- package/dist/chunk-SYQ7R2JO.js.map +1 -0
- package/dist/chunk-TD643KB3.js +245 -0
- package/dist/chunk-TD643KB3.js.map +1 -0
- package/dist/chunk-TFV6Z7F7.js +129 -0
- package/dist/chunk-TFV6Z7F7.js.map +1 -0
- package/dist/chunk-TGOHJCQ4.js +83 -0
- package/dist/chunk-TGOHJCQ4.js.map +1 -0
- package/dist/chunk-TOPAIL5W.js +22 -0
- package/dist/chunk-TOPAIL5W.js.map +1 -0
- package/dist/chunk-U4VYHKPM.js +110 -0
- package/dist/chunk-U4VYHKPM.js.map +1 -0
- package/dist/chunk-UFWNMW3G.js +392 -0
- package/dist/chunk-UFWNMW3G.js.map +1 -0
- package/dist/chunk-UNHCZRO4.js +64 -0
- package/dist/chunk-UNHCZRO4.js.map +1 -0
- package/dist/chunk-URDV4OCP.js +308 -0
- package/dist/chunk-URDV4OCP.js.map +1 -0
- package/dist/chunk-YI6JVSFO.js +43 -0
- package/dist/chunk-YI6JVSFO.js.map +1 -0
- package/dist/chunk-YNSNRR5D.js +184 -0
- package/dist/chunk-YNSNRR5D.js.map +1 -0
- package/dist/chunk-Z6DLWTBY.js +46 -0
- package/dist/chunk-Z6DLWTBY.js.map +1 -0
- package/dist/chunk-ZDQIUHAM.js +89 -0
- package/dist/chunk-ZDQIUHAM.js.map +1 -0
- package/dist/chunk-ZSKHDU5P.js +124 -0
- package/dist/chunk-ZSKHDU5P.js.map +1 -0
- package/dist/cli-v2/defaults/agent-mappings.yaml +185 -0
- package/dist/commands/build/marketplace.js +295 -0
- package/dist/commands/build/marketplace.js.map +1 -0
- package/dist/commands/build/plugins.js +362 -0
- package/dist/commands/build/plugins.js.map +1 -0
- package/dist/commands/build/stack.js +169 -0
- package/dist/commands/build/stack.js.map +1 -0
- package/dist/commands/compile.js +461 -0
- package/dist/commands/compile.js.map +1 -0
- package/dist/commands/config/get.js +60 -0
- package/dist/commands/config/get.js.map +1 -0
- package/dist/commands/config/index.js +22 -0
- package/dist/commands/config/index.js.map +1 -0
- package/dist/commands/config/path.js +35 -0
- package/dist/commands/config/path.js.map +1 -0
- package/dist/commands/config/set-project.js +61 -0
- package/dist/commands/config/set-project.js.map +1 -0
- package/dist/commands/config/set.js +60 -0
- package/dist/commands/config/set.js.map +1 -0
- package/dist/commands/config/show.js +13 -0
- package/dist/commands/config/show.js.map +1 -0
- package/dist/commands/config/unset-project.js +57 -0
- package/dist/commands/config/unset-project.js.map +1 -0
- package/dist/commands/config/unset.js +56 -0
- package/dist/commands/config/unset.js.map +1 -0
- package/dist/commands/diff.js +755 -0
- package/dist/commands/diff.js.map +1 -0
- package/dist/commands/doctor.js +413 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/edit.js +253 -0
- package/dist/commands/edit.js.map +1 -0
- package/dist/commands/eject.js +208 -0
- package/dist/commands/eject.js.map +1 -0
- package/dist/commands/info.js +205 -0
- package/dist/commands/info.js.map +1 -0
- package/dist/commands/init.js +914 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/list.js +44 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/new/agent.js +230 -0
- package/dist/commands/new/agent.js.map +1 -0
- package/dist/commands/new/skill.js +204 -0
- package/dist/commands/new/skill.js.map +1 -0
- package/dist/commands/outdated.js +242 -0
- package/dist/commands/outdated.js.map +1 -0
- package/dist/commands/search.js +115 -0
- package/dist/commands/search.js.map +1 -0
- package/dist/commands/test-imports.js +92 -0
- package/dist/commands/test-imports.js.map +1 -0
- package/dist/commands/uninstall.js +302 -0
- package/dist/commands/uninstall.js.map +1 -0
- package/dist/commands/update.js +428 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/commands/validate.js +375 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/commands/version/bump.js +95 -0
- package/dist/commands/version/bump.js.map +1 -0
- package/dist/commands/version/index.js +70 -0
- package/dist/commands/version/index.js.map +1 -0
- package/dist/commands/version/set.js +101 -0
- package/dist/commands/version/set.js.map +1 -0
- package/dist/commands/version/show.js +70 -0
- package/dist/commands/version/show.js.map +1 -0
- package/dist/components/common/confirm.js +9 -0
- package/dist/components/common/confirm.js.map +1 -0
- package/dist/components/common/message.js +24 -0
- package/dist/components/common/message.js.map +1 -0
- package/dist/components/common/spinner.js +14 -0
- package/dist/components/common/spinner.js.map +1 -0
- package/dist/components/wizard/selection-header.js +11 -0
- package/dist/components/wizard/selection-header.js.map +1 -0
- package/dist/components/wizard/step-approach.js +11 -0
- package/dist/components/wizard/step-approach.js.map +1 -0
- package/dist/components/wizard/step-category.js +12 -0
- package/dist/components/wizard/step-category.js.map +1 -0
- package/dist/components/wizard/step-confirm.js +12 -0
- package/dist/components/wizard/step-confirm.js.map +1 -0
- package/dist/components/wizard/step-stack.js +11 -0
- package/dist/components/wizard/step-stack.js.map +1 -0
- package/dist/components/wizard/step-subcategory.js +13 -0
- package/dist/components/wizard/step-subcategory.js.map +1 -0
- package/dist/components/wizard/wizard.js +19 -0
- package/dist/components/wizard/wizard.js.map +1 -0
- package/dist/hooks/init.js +41 -0
- package/dist/hooks/init.js.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/magic-string.es-RGXYGAW3.js +1316 -0
- package/dist/magic-string.es-RGXYGAW3.js.map +1 -0
- package/dist/stores/wizard-store.js +10 -0
- package/dist/stores/wizard-store.js.map +1 -0
- package/dist/stores/wizard-store.test.js +15991 -0
- package/dist/stores/wizard-store.test.js.map +1 -0
- package/package.json +44 -25
- package/dist/cli/index.js +0 -6314
- package/dist/cli/index.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli-v2/lib/loader.ts","../src/cli-v2/lib/stacks-loader.ts","../src/cli-v2/lib/matrix-loader.ts"],"sourcesContent":["import { parse as parseYaml } from \"yaml\";\nimport path from \"path\";\nimport { glob, readFile, directoryExists } from \"../utils/fs\";\nimport { verbose } from \"../utils/logger\";\nimport { DIRS } from \"../consts\";\nimport type {\n AgentDefinition,\n AgentYamlConfig,\n SkillDefinition,\n SkillFrontmatter,\n StackConfig,\n} from \"../types\";\n\nexport type CompileMode = \"dev\";\n\nexport function getDirs(_mode: CompileMode) {\n return DIRS;\n}\n\nconst FRONTMATTER_REGEX = /^---\\n([\\s\\S]*?)\\n---/;\n\nexport function parseFrontmatter(content: string): SkillFrontmatter | null {\n const match = content.match(FRONTMATTER_REGEX);\n if (!match) return null;\n\n const yamlContent = match[1];\n const frontmatter = parseYaml(yamlContent) as SkillFrontmatter;\n\n if (!frontmatter.name || !frontmatter.description) return null;\n return frontmatter;\n}\n\nfunction extractDisplayName(skillId: string): string {\n const withoutCategory = skillId.split(\"/\").pop() || skillId;\n const withoutAuthor = withoutCategory.replace(/\\s*\\(@\\w+\\)$/, \"\").trim();\n return withoutAuthor\n .split(\"-\")\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(\" \");\n}\n\nexport async function loadAllAgents(\n projectRoot: string,\n): Promise<Record<string, AgentDefinition>> {\n const agents: Record<string, AgentDefinition> = {};\n const agentSourcesDir = path.join(projectRoot, DIRS.agents);\n\n const files = await glob(\"**/agent.yaml\", agentSourcesDir);\n\n for (const file of files) {\n const fullPath = path.join(agentSourcesDir, file);\n const content = await readFile(fullPath);\n const config = parseYaml(content) as AgentYamlConfig;\n const agentPath = path.dirname(file);\n\n agents[config.id] = {\n title: config.title,\n description: config.description,\n model: config.model,\n tools: config.tools,\n path: agentPath,\n sourceRoot: projectRoot,\n skills: config.skills,\n };\n\n verbose(`Loaded agent: ${config.id} from ${file}`);\n }\n\n return agents;\n}\n\n/** @deprecated Use loadSkillsByIds instead - stacks no longer embed skills */\nexport async function loadStackSkills(\n stackId: string,\n projectRoot: string,\n _mode: CompileMode = \"dev\",\n): Promise<Record<string, SkillDefinition>> {\n const skills: Record<string, SkillDefinition> = {};\n const stackSkillsDir = path.join(projectRoot, DIRS.stacks, stackId, \"skills\");\n\n if (!(await directoryExists(stackSkillsDir))) {\n verbose(`No embedded skills directory for stack ${stackId}`);\n return skills;\n }\n\n const files = await glob(\"**/SKILL.md\", stackSkillsDir);\n\n for (const file of files) {\n const fullPath = path.join(stackSkillsDir, file);\n const content = await readFile(fullPath);\n\n const frontmatter = parseFrontmatter(content);\n if (!frontmatter) {\n console.warn(\n ` Warning: Skipping ${file}: Missing or invalid frontmatter`,\n );\n continue;\n }\n\n const folderPath = file.replace(\"/SKILL.md\", \"\");\n const skillPath = `src/stacks/${stackId}/skills/${folderPath}/`;\n const skillId = frontmatter.name;\n\n skills[skillId] = {\n path: skillPath,\n name: extractDisplayName(frontmatter.name),\n description: frontmatter.description,\n canonicalId: skillId,\n };\n\n verbose(`Loaded stack skill: ${skillId} from ${file}`);\n }\n\n return skills;\n}\n\nasync function buildIdToDirectoryPathMap(\n skillsDir: string,\n): Promise<Record<string, string>> {\n const map: Record<string, string> = {};\n const files = await glob(\"**/SKILL.md\", skillsDir);\n\n for (const file of files) {\n const fullPath = path.join(skillsDir, file);\n const content = await readFile(fullPath);\n const frontmatter = parseFrontmatter(content);\n\n if (frontmatter?.name) {\n const directoryPath = file.replace(\"/SKILL.md\", \"\");\n map[frontmatter.name] = directoryPath;\n map[directoryPath] = directoryPath;\n }\n }\n\n return map;\n}\n\nexport async function loadSkillsByIds(\n skillIds: Array<{ id: string }>,\n projectRoot: string,\n): Promise<Record<string, SkillDefinition>> {\n const skills: Record<string, SkillDefinition> = {};\n const skillsDir = path.join(projectRoot, DIRS.skills);\n\n const idToDirectoryPath = await buildIdToDirectoryPathMap(skillsDir);\n const allSkillIds = Object.keys(idToDirectoryPath);\n const expandedSkillIds: string[] = [];\n\n for (const { id: skillId } of skillIds) {\n if (idToDirectoryPath[skillId]) {\n expandedSkillIds.push(skillId);\n } else {\n const childSkills = allSkillIds.filter((id) => {\n const dirPath = idToDirectoryPath[id];\n return dirPath.startsWith(skillId + \"/\");\n });\n\n if (childSkills.length > 0) {\n expandedSkillIds.push(...childSkills);\n verbose(\n `Expanded directory '${skillId}' to ${childSkills.length} skills`,\n );\n } else {\n console.warn(` Warning: Unknown skill reference '${skillId}'`);\n }\n }\n }\n\n const uniqueSkillIds = [...new Set(expandedSkillIds)];\n\n for (const skillId of uniqueSkillIds) {\n const directoryPath = idToDirectoryPath[skillId];\n if (!directoryPath) {\n console.warn(\n ` Warning: Could not find skill ${skillId}: No matching skill found`,\n );\n continue;\n }\n\n const skillPath = path.join(skillsDir, directoryPath);\n const skillMdPath = path.join(skillPath, \"SKILL.md\");\n\n try {\n const content = await readFile(skillMdPath);\n const frontmatter = parseFrontmatter(content);\n\n if (!frontmatter) {\n console.warn(\n ` Warning: Skipping ${skillId}: Missing or invalid frontmatter`,\n );\n continue;\n }\n\n const canonicalId = frontmatter.name;\n const skillDef: SkillDefinition = {\n path: `${DIRS.skills}/${directoryPath}/`,\n name: extractDisplayName(frontmatter.name),\n description: frontmatter.description,\n canonicalId,\n };\n\n skills[canonicalId] = skillDef;\n\n if (directoryPath !== canonicalId) {\n skills[directoryPath] = skillDef;\n }\n\n verbose(`Loaded skill: ${canonicalId} (from ${directoryPath})`);\n } catch (error) {\n console.warn(` Warning: Could not load skill ${skillId}: ${error}`);\n }\n }\n\n return skills;\n}\n\nexport async function loadPluginSkills(\n pluginDir: string,\n): Promise<Record<string, SkillDefinition>> {\n const skills: Record<string, SkillDefinition> = {};\n const pluginSkillsDir = path.join(pluginDir, \"skills\");\n\n if (!(await directoryExists(pluginSkillsDir))) {\n return skills;\n }\n\n const files = await glob(\"**/SKILL.md\", pluginSkillsDir);\n\n for (const file of files) {\n const fullPath = path.join(pluginSkillsDir, file);\n const content = await readFile(fullPath);\n\n const frontmatter = parseFrontmatter(content);\n if (!frontmatter) {\n console.warn(\n ` Warning: Skipping ${file}: Missing or invalid frontmatter`,\n );\n continue;\n }\n\n const folderPath = file.replace(\"/SKILL.md\", \"\");\n const skillPath = `skills/${folderPath}/`;\n const skillId = frontmatter.name;\n\n skills[skillId] = {\n path: skillPath,\n name: extractDisplayName(frontmatter.name),\n description: frontmatter.description,\n canonicalId: skillId,\n };\n\n verbose(`Loaded plugin skill: ${skillId} from ${file}`);\n }\n\n return skills;\n}\n\nconst stackCache = new Map<string, StackConfig>();\n\n/**\n * @deprecated Use loadStackById from stacks-loader.ts instead.\n * This function loads legacy stack configs from src/stacks/{stackId}/config.yaml.\n * The new system uses config/stacks.yaml with agent-centric configuration\n * where skills are defined in each agent's agent.yaml file.\n *\n * Migration path:\n * 1. Use loadStackById() to get stack metadata (agents list)\n * 2. Skills come from agent.yaml files, not stack config\n *\n * @see src/cli-v2/lib/stacks-loader.ts\n */\nexport async function loadStack(\n stackId: string,\n projectRoot: string,\n mode: CompileMode = \"dev\",\n): Promise<StackConfig> {\n const cacheKey = `${mode}:${stackId}`;\n const cached = stackCache.get(cacheKey);\n if (cached) return cached;\n\n const dirs = getDirs(mode);\n const stackPath = path.join(projectRoot, dirs.stacks, stackId, \"config.yaml\");\n\n try {\n const content = await readFile(stackPath);\n const stack = parseYaml(content) as StackConfig;\n stackCache.set(cacheKey, stack);\n verbose(`Loaded stack: ${stack.name} (${stackId})`);\n return stack;\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n throw new Error(\n `Failed to load stack '${stackId}': ${errorMessage}. Expected config at: ${stackPath}`,\n );\n }\n}\n","import { parse as parseYaml } from \"yaml\";\nimport path from \"path\";\nimport { readFile, fileExists } from \"../utils/fs\";\nimport { verbose } from \"../utils/logger\";\nimport type { Stack, StacksConfig, StackAgentConfig } from \"../types-stacks\";\nimport type { SkillReference } from \"../types\";\n\nconst STACKS_FILE = \"config/stacks.yaml\";\n\nconst stacksCache = new Map<string, Stack[]>();\n\n/**\n * Load all stacks from config/stacks.yaml\n * Stacks are simple agent groupings without skill mappings\n */\nexport async function loadStacks(configDir: string): Promise<Stack[]> {\n const cacheKey = configDir;\n const cached = stacksCache.get(cacheKey);\n if (cached) return cached;\n\n const stacksPath = path.join(configDir, STACKS_FILE);\n\n if (!(await fileExists(stacksPath))) {\n verbose(`No stacks file found at ${stacksPath}`);\n return [];\n }\n\n try {\n const content = await readFile(stacksPath);\n const config = parseYaml(content) as StacksConfig;\n\n if (!config.stacks || !Array.isArray(config.stacks)) {\n verbose(`Invalid stacks.yaml format: missing stacks array`);\n return [];\n }\n\n stacksCache.set(cacheKey, config.stacks);\n verbose(`Loaded ${config.stacks.length} stacks from ${stacksPath}`);\n\n return config.stacks;\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n throw new Error(\n `Failed to load stacks from '${stacksPath}': ${errorMessage}`,\n );\n }\n}\n\n/**\n * Load a specific stack by ID\n * Returns null if stack not found\n */\nexport async function loadStackById(\n stackId: string,\n configDir: string,\n): Promise<Stack | null> {\n const stacks = await loadStacks(configDir);\n const stack = stacks.find((s) => s.id === stackId);\n\n if (!stack) {\n verbose(`Stack '${stackId}' not found`);\n return null;\n }\n\n verbose(`Found stack: ${stack.name} (${stackId})`);\n return stack;\n}\n\n/**\n * Subcategories considered \"key\" skills that should be preloaded.\n * These are primary technology choices that define the stack's core.\n */\nconst KEY_SUBCATEGORIES = new Set([\n \"framework\",\n \"api\",\n \"database\",\n \"meta-framework\",\n \"base-framework\",\n \"platform\",\n]);\n\n/**\n * Resolve a single agent's technology config to skill references.\n * Looks up each technology alias in skill_aliases to get full skill ID.\n *\n * @param agentConfig - The agent's technology selections (subcategory -> alias)\n * @param skillAliases - Mapping from technology aliases to full skill IDs\n * @returns Array of SkillReference objects\n */\nexport function resolveAgentConfigToSkills(\n agentConfig: StackAgentConfig,\n skillAliases: Record<string, string>,\n): SkillReference[] {\n const skillRefs: SkillReference[] = [];\n\n for (const [subcategory, technologyAlias] of Object.entries(agentConfig)) {\n const fullSkillId = skillAliases[technologyAlias];\n\n if (!fullSkillId) {\n verbose(\n `Warning: No skill alias found for '${technologyAlias}' (subcategory: ${subcategory}). Skipping.`,\n );\n continue;\n }\n\n const isKeySkill = KEY_SUBCATEGORIES.has(subcategory);\n\n skillRefs.push({\n id: fullSkillId,\n usage: `when working with ${subcategory}`,\n preloaded: isKeySkill,\n });\n }\n\n return skillRefs;\n}\n\n/**\n * Resolve all agents in a stack to their skill references.\n * Takes a Stack and skill_aliases, returns a mapping of agent IDs to their resolved skills.\n *\n * @param stack - The stack definition with agent technology selections\n * @param skillAliases - Mapping from technology aliases to full skill IDs\n * @returns Record mapping agent IDs to their SkillReference arrays\n *\n * @example\n * ```typescript\n * const stack = {\n * id: 'nextjs-fullstack',\n * name: 'Next.js Fullstack',\n * agents: {\n * 'web-developer': { framework: 'react', styling: 'scss-modules' },\n * 'api-developer': { api: 'hono', database: 'drizzle' }\n * }\n * };\n *\n * const aliases = {\n * react: 'web/framework/react (@vince)',\n * hono: 'api/framework/hono (@vince)',\n * // ...\n * };\n *\n * const result = resolveStackSkillsFromAliases(stack, aliases);\n * // Returns:\n * // {\n * // 'web-developer': [{ id: 'web/framework/react (@vince)', usage: '...', preloaded: true }, ...],\n * // 'api-developer': [{ id: 'api/framework/hono (@vince)', usage: '...', preloaded: true }, ...]\n * // }\n * ```\n */\nexport function resolveStackSkillsFromAliases(\n stack: Stack,\n skillAliases: Record<string, string>,\n): Record<string, SkillReference[]> {\n const result: Record<string, SkillReference[]> = {};\n\n for (const [agentId, agentConfig] of Object.entries(stack.agents)) {\n // Empty config {} means agent has no technology-specific skills\n if (Object.keys(agentConfig).length === 0) {\n result[agentId] = [];\n continue;\n }\n\n result[agentId] = resolveAgentConfigToSkills(agentConfig, skillAliases);\n }\n\n verbose(\n `Resolved skills for ${Object.keys(result).length} agents in stack '${stack.id}'`,\n );\n\n return result;\n}\n","import { parse as parseYaml } from \"yaml\";\nimport path from \"path\";\nimport { glob, readFile, fileExists } from \"../utils/fs\";\nimport { verbose } from \"../utils/logger\";\nimport { DIRS } from \"../consts\";\nimport { parseFrontmatter } from \"./loader\";\nimport type {\n SkillsMatrixConfig,\n ExtractedSkillMetadata,\n MergedSkillsMatrix,\n ResolvedSkill,\n ResolvedStack,\n SkillRelation,\n SkillRequirement,\n SkillAlternative,\n} from \"../types-matrix\";\n\ninterface RawMetadata {\n category: string;\n category_exclusive?: boolean;\n author: string;\n version: string;\n cli_name?: string;\n cli_description?: string;\n usage_guidance?: string;\n tags?: string[];\n compatible_with?: string[];\n conflicts_with?: string[];\n requires?: string[];\n requires_setup?: string[];\n provides_setup_for?: string[];\n}\n\nexport async function loadSkillsMatrix(\n configPath: string,\n): Promise<SkillsMatrixConfig> {\n const content = await readFile(configPath);\n const config = parseYaml(content) as SkillsMatrixConfig;\n\n validateMatrixStructure(config, configPath);\n\n verbose(`Loaded skills matrix: ${configPath}`);\n return config;\n}\n\nfunction validateMatrixStructure(\n config: SkillsMatrixConfig,\n configPath: string,\n): void {\n // Note: suggested_stacks removed from required - stacks now defined in config/stacks.yaml (Phase 6)\n const requiredFields = [\n \"version\",\n \"categories\",\n \"relationships\",\n \"skill_aliases\",\n ];\n const missing = requiredFields.filter((field) => !(field in config));\n\n if (missing.length > 0) {\n throw new Error(\n `Skills matrix at ${configPath} is missing required fields: ${missing.join(\", \")}`,\n );\n }\n\n const relationshipFields = [\n \"conflicts\",\n \"recommends\",\n \"requires\",\n \"alternatives\",\n ];\n const missingRelationships = relationshipFields.filter(\n (field) => !config.relationships || !(field in config.relationships),\n );\n\n if (missingRelationships.length > 0) {\n throw new Error(\n `Skills matrix relationships missing required fields: ${missingRelationships.join(\", \")}`,\n );\n }\n\n for (const [categoryId, category] of Object.entries(config.categories)) {\n const requiredCategoryFields = [\n \"id\",\n \"name\",\n \"description\",\n \"exclusive\",\n \"required\",\n \"order\",\n ];\n const missingCategoryFields = requiredCategoryFields.filter(\n (field) => !(field in category),\n );\n\n if (missingCategoryFields.length > 0) {\n throw new Error(\n `Category \"${categoryId}\" missing required fields: ${missingCategoryFields.join(\", \")}`,\n );\n }\n }\n}\n\nexport async function extractAllSkills(\n skillsDir: string,\n): Promise<ExtractedSkillMetadata[]> {\n const skills: ExtractedSkillMetadata[] = [];\n const metadataFiles = await glob(\"**/metadata.yaml\", skillsDir);\n\n for (const metadataFile of metadataFiles) {\n const skillDir = path.dirname(metadataFile);\n const skillMdPath = path.join(skillsDir, skillDir, \"SKILL.md\");\n const metadataPath = path.join(skillsDir, metadataFile);\n\n if (!(await fileExists(skillMdPath))) {\n verbose(`Skipping ${metadataFile}: No SKILL.md found`);\n continue;\n }\n\n const metadataContent = await readFile(metadataPath);\n const metadata = parseYaml(metadataContent) as RawMetadata;\n const skillMdContent = await readFile(skillMdPath);\n const frontmatter = parseFrontmatter(skillMdContent);\n\n if (!frontmatter) {\n verbose(`Skipping ${metadataFile}: Invalid SKILL.md frontmatter`);\n continue;\n }\n\n if (!metadata.cli_name) {\n throw new Error(\n `Skill at ${metadataFile} is missing required 'cli_name' field in metadata.yaml`,\n );\n }\n\n const skillId = frontmatter.name;\n\n const extracted: ExtractedSkillMetadata = {\n id: skillId,\n directoryPath: skillDir,\n name: `${metadata.cli_name} ${metadata.author}`,\n description: metadata.cli_description || frontmatter.description,\n usageGuidance: metadata.usage_guidance,\n category: metadata.category,\n categoryExclusive: metadata.category_exclusive ?? true,\n author: metadata.author,\n tags: metadata.tags ?? [],\n compatibleWith: metadata.compatible_with ?? [],\n conflictsWith: metadata.conflicts_with ?? [],\n requires: metadata.requires ?? [],\n requiresSetup: metadata.requires_setup ?? [],\n providesSetupFor: metadata.provides_setup_for ?? [],\n path: `skills/${skillDir}/`,\n };\n\n skills.push(extracted);\n verbose(`Extracted skill: ${skillId}`);\n }\n\n return skills;\n}\n\nfunction buildReverseAliases(\n aliases: Record<string, string>,\n): Record<string, string> {\n const reverse: Record<string, string> = {};\n for (const [alias, fullId] of Object.entries(aliases)) {\n reverse[fullId] = alias;\n }\n return reverse;\n}\n\n/**\n * Build a map from short names to actual skill IDs.\n *\n * This handles multiple formats used in skill metadata:\n * - \"react (@vince)\" -> \"web/framework/react (@vince)\"\n * - \"react\" -> \"web/framework/react (@vince)\"\n * - Old alias targets that may still exist in metadata files\n */\nfunction buildAliasTargetToSkillIdMap(\n aliases: Record<string, string>,\n skills: ExtractedSkillMetadata[],\n): Record<string, string> {\n const map: Record<string, string> = {};\n\n for (const skill of skills) {\n // Extract the \"short author\" form: last path segment with author\n // e.g., \"web/framework/react (@vince)\" -> \"react (@vince)\"\n const parts = skill.id.split(\"/\");\n const shortForm = parts[parts.length - 1];\n\n if (shortForm && shortForm !== skill.id) {\n map[shortForm] = skill.id;\n }\n\n // Also map directory name without author if different\n // e.g., \"web/framework/react\" -> \"web/framework/react (@vince)\"\n if (skill.directoryPath && skill.directoryPath !== skill.id) {\n map[skill.directoryPath] = skill.id;\n }\n }\n\n // Also include any old-style alias targets that might still be referenced\n const aliasTargets = new Set(Object.values(aliases));\n for (const skill of skills) {\n for (const aliasTarget of aliasTargets) {\n if (\n aliasTarget !== skill.id &&\n (skill.id.endsWith(`/${aliasTarget}`) || skill.id === aliasTarget)\n ) {\n map[aliasTarget] = skill.id;\n }\n }\n }\n\n return map;\n}\n\nfunction buildDirectoryPathToIdMap(\n skills: ExtractedSkillMetadata[],\n): Record<string, string> {\n const map: Record<string, string> = {};\n for (const skill of skills) {\n if (skill.directoryPath && skill.directoryPath !== skill.id) {\n map[skill.directoryPath] = skill.id;\n }\n }\n return map;\n}\n\nfunction resolveToCanonicalId(\n aliasOrId: string,\n aliases: Record<string, string>,\n directoryPathToId: Record<string, string> = {},\n aliasTargetToSkillId: Record<string, string> = {},\n): string {\n if (aliases[aliasOrId]) {\n return aliases[aliasOrId];\n }\n if (directoryPathToId[aliasOrId]) {\n return directoryPathToId[aliasOrId];\n }\n // Handle \"short author\" format like \"react (@vince)\" that maps to full ID\n if (aliasTargetToSkillId[aliasOrId]) {\n return aliasTargetToSkillId[aliasOrId];\n }\n return aliasOrId;\n}\n\nexport async function mergeMatrixWithSkills(\n matrix: SkillsMatrixConfig,\n skills: ExtractedSkillMetadata[],\n): Promise<MergedSkillsMatrix> {\n const aliases = matrix.skill_aliases;\n const aliasesReverse = buildReverseAliases(aliases);\n const directoryPathToId = buildDirectoryPathToIdMap(skills);\n const aliasTargetToSkillId = buildAliasTargetToSkillIdMap(aliases, skills);\n const resolvedSkills: Record<string, ResolvedSkill> = {};\n\n for (const skill of skills) {\n const resolved = buildResolvedSkill(\n skill,\n matrix,\n aliases,\n aliasesReverse,\n directoryPathToId,\n aliasTargetToSkillId,\n );\n resolvedSkills[skill.id] = resolved;\n }\n\n computeInverseRelationships(resolvedSkills);\n const suggestedStacks = resolveSuggestedStacks(\n matrix,\n aliases,\n aliasTargetToSkillId,\n );\n\n const merged: MergedSkillsMatrix = {\n version: matrix.version,\n categories: matrix.categories,\n skills: resolvedSkills,\n suggestedStacks,\n aliases,\n aliasesReverse,\n generatedAt: new Date().toISOString(),\n };\n\n return merged;\n}\n\nfunction buildResolvedSkill(\n skill: ExtractedSkillMetadata,\n matrix: SkillsMatrixConfig,\n aliases: Record<string, string>,\n aliasesReverse: Record<string, string>,\n directoryPathToId: Record<string, string>,\n aliasTargetToSkillId: Record<string, string>,\n): ResolvedSkill {\n const conflictsWith: SkillRelation[] = [];\n const recommends: SkillRelation[] = [];\n const requires: SkillRequirement[] = [];\n const alternatives: SkillAlternative[] = [];\n const discourages: SkillRelation[] = [];\n\n // Helper to resolve with all maps\n const resolve = (id: string) =>\n resolveToCanonicalId(id, aliases, directoryPathToId, aliasTargetToSkillId);\n\n for (const conflictRef of skill.conflictsWith) {\n const canonicalId = resolve(conflictRef);\n conflictsWith.push({\n skillId: canonicalId,\n reason: \"Defined in skill metadata\",\n });\n }\n\n for (const conflictRule of matrix.relationships.conflicts) {\n const resolvedSkills = conflictRule.skills.map(resolve);\n if (resolvedSkills.includes(skill.id)) {\n for (const otherSkill of resolvedSkills) {\n if (otherSkill !== skill.id) {\n if (!conflictsWith.some((c) => c.skillId === otherSkill)) {\n conflictsWith.push({\n skillId: otherSkill,\n reason: conflictRule.reason,\n });\n }\n }\n }\n }\n }\n\n for (const compatRef of skill.compatibleWith) {\n const canonicalId = resolve(compatRef);\n recommends.push({\n skillId: canonicalId,\n reason: \"Compatible with this skill\",\n });\n }\n\n for (const recommendRule of matrix.relationships.recommends) {\n const whenCanonicalId = resolve(recommendRule.when);\n if (whenCanonicalId === skill.id) {\n for (const suggested of recommendRule.suggest) {\n const canonicalId = resolve(suggested);\n if (!recommends.some((r) => r.skillId === canonicalId)) {\n recommends.push({\n skillId: canonicalId,\n reason: recommendRule.reason,\n });\n }\n }\n }\n }\n\n if (skill.requires.length > 0) {\n requires.push({\n skillIds: skill.requires.map(resolve),\n needsAny: false,\n reason: \"Defined in skill metadata\",\n });\n }\n\n for (const requireRule of matrix.relationships.requires) {\n const skillCanonicalId = resolve(requireRule.skill);\n if (skillCanonicalId === skill.id) {\n requires.push({\n skillIds: requireRule.needs.map(resolve),\n needsAny: requireRule.needs_any ?? false,\n reason: requireRule.reason,\n });\n }\n }\n\n for (const altGroup of matrix.relationships.alternatives) {\n const resolvedAlts = altGroup.skills.map(resolve);\n if (resolvedAlts.includes(skill.id)) {\n for (const altSkill of resolvedAlts) {\n if (altSkill !== skill.id) {\n alternatives.push({\n skillId: altSkill,\n purpose: altGroup.purpose,\n });\n }\n }\n }\n }\n\n if (matrix.relationships.discourages) {\n for (const discourageRule of matrix.relationships.discourages) {\n const resolvedSkills = discourageRule.skills.map(resolve);\n if (resolvedSkills.includes(skill.id)) {\n for (const otherSkill of resolvedSkills) {\n if (otherSkill !== skill.id) {\n if (!discourages.some((d) => d.skillId === otherSkill)) {\n discourages.push({\n skillId: otherSkill,\n reason: discourageRule.reason,\n });\n }\n }\n }\n }\n }\n }\n\n return {\n id: skill.id,\n alias: aliasesReverse[skill.id],\n name: skill.name,\n description: skill.description,\n usageGuidance: skill.usageGuidance,\n category: skill.category,\n categoryExclusive: skill.categoryExclusive,\n tags: skill.tags,\n author: skill.author,\n conflictsWith,\n recommends,\n recommendedBy: [],\n requires,\n requiredBy: [],\n alternatives,\n discourages,\n requiresSetup: skill.requiresSetup.map(resolve),\n providesSetupFor: skill.providesSetupFor.map(resolve),\n path: skill.path,\n };\n}\n\nfunction computeInverseRelationships(\n skills: Record<string, ResolvedSkill>,\n): void {\n for (const skill of Object.values(skills)) {\n for (const recommend of skill.recommends) {\n const targetSkill = skills[recommend.skillId];\n if (targetSkill) {\n targetSkill.recommendedBy.push({\n skillId: skill.id,\n reason: recommend.reason,\n });\n }\n }\n\n for (const requirement of skill.requires) {\n for (const requiredId of requirement.skillIds) {\n const targetSkill = skills[requiredId];\n if (targetSkill) {\n targetSkill.requiredBy.push({\n skillId: skill.id,\n reason: requirement.reason,\n });\n }\n }\n }\n }\n}\n\nfunction resolveSuggestedStacks(\n matrix: SkillsMatrixConfig,\n aliases: Record<string, string>,\n aliasTargetToSkillId: Record<string, string>,\n): ResolvedStack[] {\n // Phase 6: suggested_stacks is now optional (stacks moved to config/stacks.yaml)\n if (!matrix.suggested_stacks) {\n return [];\n }\n return matrix.suggested_stacks.map((stack) => {\n const resolvedSkillsMap: Record<string, Record<string, string>> = {};\n const allSkillIds: string[] = [];\n\n for (const [category, subcategories] of Object.entries(stack.skills)) {\n resolvedSkillsMap[category] = {};\n for (const [subcategory, alias] of Object.entries(subcategories)) {\n // First resolve the alias to its target (e.g., \"react\" -> \"react (@vince)\")\n const aliasTarget = resolveToCanonicalId(alias, aliases);\n // Then check if the alias target needs to be mapped to a full skill ID\n // (e.g., \"react (@vince)\" -> \"web/framework/react (@vince)\")\n const canonicalId = aliasTargetToSkillId[aliasTarget] || aliasTarget;\n resolvedSkillsMap[category][subcategory] = canonicalId;\n allSkillIds.push(canonicalId);\n }\n }\n\n return {\n id: stack.id,\n name: stack.name,\n description: stack.description,\n audience: stack.audience,\n skills: resolvedSkillsMap,\n allSkillIds,\n philosophy: stack.philosophy,\n };\n });\n}\n\nexport async function loadAndMergeSkillsMatrix(\n matrixPath: string,\n projectRoot: string,\n): Promise<MergedSkillsMatrix> {\n const matrix = await loadSkillsMatrix(matrixPath);\n const skillsDir = path.join(projectRoot, DIRS.skills);\n const skills = await extractAllSkills(skillsDir);\n return mergeMatrixWithSkills(matrix, skills);\n}\n"],"mappings":"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","names":["parseYaml","path","path","parseYaml","parseYaml","path","parseYaml","path"]}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
getTopLevelCategories
|
|
4
|
+
} from "./chunk-AZP2AA5M.js";
|
|
5
|
+
import {
|
|
6
|
+
useWizardStore
|
|
7
|
+
} from "./chunk-6OY6ZYQF.js";
|
|
8
|
+
import {
|
|
9
|
+
init_esm_shims
|
|
10
|
+
} from "./chunk-DHET7RCE.js";
|
|
11
|
+
|
|
12
|
+
// src/cli-v2/components/wizard/step-category.tsx
|
|
13
|
+
init_esm_shims();
|
|
14
|
+
import { Box, Text } from "ink";
|
|
15
|
+
import { Select } from "@inkjs/ui";
|
|
16
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
17
|
+
var BACK_VALUE = "__back__";
|
|
18
|
+
var CONTINUE_VALUE = "__continue__";
|
|
19
|
+
var StepCategory = ({ matrix }) => {
|
|
20
|
+
const {
|
|
21
|
+
selectedSkills,
|
|
22
|
+
visitedCategories,
|
|
23
|
+
setCategory,
|
|
24
|
+
setStep,
|
|
25
|
+
goBack,
|
|
26
|
+
markCategoryVisited
|
|
27
|
+
} = useWizardStore();
|
|
28
|
+
const topCategoryIds = getTopLevelCategories(matrix);
|
|
29
|
+
const unvisitedCategories = topCategoryIds.filter(
|
|
30
|
+
(catId) => !visitedCategories.has(catId)
|
|
31
|
+
);
|
|
32
|
+
const options = [
|
|
33
|
+
{ value: BACK_VALUE, label: "\u2190 Back" }
|
|
34
|
+
];
|
|
35
|
+
if (selectedSkills.length > 0) {
|
|
36
|
+
options.push({
|
|
37
|
+
value: CONTINUE_VALUE,
|
|
38
|
+
label: `\u2192 Continue with ${selectedSkills.length} skill(s)`
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
for (const catId of topCategoryIds) {
|
|
42
|
+
const cat = matrix.categories[catId];
|
|
43
|
+
const isVisited = visitedCategories.has(catId);
|
|
44
|
+
const label = isVisited ? cat.name : `${cat.name} (new)`;
|
|
45
|
+
options.push({ value: catId, label });
|
|
46
|
+
}
|
|
47
|
+
const handleSelect = (value) => {
|
|
48
|
+
if (value === BACK_VALUE) {
|
|
49
|
+
goBack();
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (value === CONTINUE_VALUE) {
|
|
53
|
+
setStep("confirm");
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
setCategory(value);
|
|
57
|
+
markCategoryVisited(value);
|
|
58
|
+
setStep("subcategory");
|
|
59
|
+
};
|
|
60
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
61
|
+
/* @__PURE__ */ jsxs(Text, { bold: true, children: [
|
|
62
|
+
"Select a category to configure (",
|
|
63
|
+
unvisitedCategories.length,
|
|
64
|
+
" remaining):"
|
|
65
|
+
] }),
|
|
66
|
+
/* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Select, { options, onChange: handleSelect }) })
|
|
67
|
+
] });
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export {
|
|
71
|
+
StepCategory
|
|
72
|
+
};
|
|
73
|
+
//# sourceMappingURL=chunk-JY4RO76L.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli-v2/components/wizard/step-category.tsx"],"sourcesContent":["import React from \"react\";\nimport { Box, Text } from \"ink\";\nimport { Select } from \"@inkjs/ui\";\nimport { useWizardStore } from \"../../stores/wizard-store.js\";\nimport { getTopLevelCategories } from \"../../lib/matrix-resolver.js\";\nimport type { MergedSkillsMatrix } from \"../../types-matrix.js\";\n\nconst BACK_VALUE = \"__back__\";\nconst CONTINUE_VALUE = \"__continue__\";\n\ninterface StepCategoryProps {\n matrix: MergedSkillsMatrix;\n}\n\nexport const StepCategory: React.FC<StepCategoryProps> = ({ matrix }) => {\n const {\n selectedSkills,\n visitedCategories,\n setCategory,\n setStep,\n goBack,\n markCategoryVisited,\n } = useWizardStore();\n\n const topCategoryIds = getTopLevelCategories(matrix);\n const unvisitedCategories = topCategoryIds.filter(\n (catId) => !visitedCategories.has(catId),\n );\n\n // Build options\n const options: Array<{ value: string; label: string }> = [\n { value: BACK_VALUE, label: \"← Back\" },\n ];\n\n // Add continue option if skills selected\n if (selectedSkills.length > 0) {\n options.push({\n value: CONTINUE_VALUE,\n label: `→ Continue with ${selectedSkills.length} skill(s)`,\n });\n }\n\n // Add category options with unvisited indicators\n for (const catId of topCategoryIds) {\n const cat = matrix.categories[catId];\n const isVisited = visitedCategories.has(catId);\n const label = isVisited ? cat.name : `${cat.name} (new)`;\n options.push({ value: catId, label });\n }\n\n const handleSelect = (value: string) => {\n if (value === BACK_VALUE) {\n goBack();\n return;\n }\n if (value === CONTINUE_VALUE) {\n setStep(\"confirm\");\n return;\n }\n\n setCategory(value);\n markCategoryVisited(value);\n setStep(\"subcategory\");\n };\n\n return (\n <Box flexDirection=\"column\">\n <Text bold>\n Select a category to configure ({unvisitedCategories.length} remaining):\n </Text>\n <Box marginTop={1}>\n <Select options={options} onChange={handleSelect} />\n </Box>\n </Box>\n );\n};\n"],"mappings":";;;;;;;;;;;;AAAA;AACA,SAAS,KAAK,YAAY;AAC1B,SAAS,cAAc;AAiEjB,SAIE,KAJF;AA5DN,IAAM,aAAa;AACnB,IAAM,iBAAiB;AAMhB,IAAM,eAA4C,CAAC,EAAE,OAAO,MAAM;AACvE,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI,eAAe;AAEnB,QAAM,iBAAiB,sBAAsB,MAAM;AACnD,QAAM,sBAAsB,eAAe;AAAA,IACzC,CAAC,UAAU,CAAC,kBAAkB,IAAI,KAAK;AAAA,EACzC;AAGA,QAAM,UAAmD;AAAA,IACvD,EAAE,OAAO,YAAY,OAAO,cAAS;AAAA,EACvC;AAGA,MAAI,eAAe,SAAS,GAAG;AAC7B,YAAQ,KAAK;AAAA,MACX,OAAO;AAAA,MACP,OAAO,wBAAmB,eAAe,MAAM;AAAA,IACjD,CAAC;AAAA,EACH;AAGA,aAAW,SAAS,gBAAgB;AAClC,UAAM,MAAM,OAAO,WAAW,KAAK;AACnC,UAAM,YAAY,kBAAkB,IAAI,KAAK;AAC7C,UAAM,QAAQ,YAAY,IAAI,OAAO,GAAG,IAAI,IAAI;AAChD,YAAQ,KAAK,EAAE,OAAO,OAAO,MAAM,CAAC;AAAA,EACtC;AAEA,QAAM,eAAe,CAAC,UAAkB;AACtC,QAAI,UAAU,YAAY;AACxB,aAAO;AACP;AAAA,IACF;AACA,QAAI,UAAU,gBAAgB;AAC5B,cAAQ,SAAS;AACjB;AAAA,IACF;AAEA,gBAAY,KAAK;AACjB,wBAAoB,KAAK;AACzB,YAAQ,aAAa;AAAA,EACvB;AAEA,SACE,qBAAC,OAAI,eAAc,UACjB;AAAA,yBAAC,QAAK,MAAI,MAAC;AAAA;AAAA,MACwB,oBAAoB;AAAA,MAAO;AAAA,OAC9D;AAAA,IACA,oBAAC,OAAI,WAAW,GACd,8BAAC,UAAO,SAAkB,UAAU,cAAc,GACpD;AAAA,KACF;AAEJ;","names":[]}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
init_esm_shims
|
|
4
|
+
} from "./chunk-DHET7RCE.js";
|
|
5
|
+
|
|
6
|
+
// src/cli-v2/utils/exec.ts
|
|
7
|
+
init_esm_shims();
|
|
8
|
+
import { spawn } from "child_process";
|
|
9
|
+
async function execCommand(command, args, options) {
|
|
10
|
+
return new Promise((resolve, reject) => {
|
|
11
|
+
const proc = spawn(command, args, {
|
|
12
|
+
cwd: options?.cwd,
|
|
13
|
+
env: { ...process.env, ...options?.env },
|
|
14
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
15
|
+
});
|
|
16
|
+
let stdout = "";
|
|
17
|
+
let stderr = "";
|
|
18
|
+
proc.stdout.on("data", (data) => {
|
|
19
|
+
stdout += data.toString();
|
|
20
|
+
});
|
|
21
|
+
proc.stderr.on("data", (data) => {
|
|
22
|
+
stderr += data.toString();
|
|
23
|
+
});
|
|
24
|
+
proc.on("close", (code) => {
|
|
25
|
+
resolve({
|
|
26
|
+
stdout,
|
|
27
|
+
stderr,
|
|
28
|
+
exitCode: code ?? 1
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
proc.on("error", (err) => {
|
|
32
|
+
reject(err);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
async function claudePluginInstall(pluginPath, scope, projectDir) {
|
|
37
|
+
const args = ["plugin", "install", pluginPath, "--scope", scope];
|
|
38
|
+
const result = await execCommand("claude", args, { cwd: projectDir });
|
|
39
|
+
if (result.exitCode !== 0) {
|
|
40
|
+
const errorMessage = result.stderr || result.stdout || "Unknown error";
|
|
41
|
+
throw new Error(`Plugin installation failed: ${errorMessage.trim()}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
async function isClaudeCLIAvailable() {
|
|
45
|
+
try {
|
|
46
|
+
const result = await execCommand("claude", ["--version"], {});
|
|
47
|
+
return result.exitCode === 0;
|
|
48
|
+
} catch {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
async function claudePluginMarketplaceList() {
|
|
53
|
+
try {
|
|
54
|
+
const result = await execCommand(
|
|
55
|
+
"claude",
|
|
56
|
+
["plugin", "marketplace", "list", "--json"],
|
|
57
|
+
{}
|
|
58
|
+
);
|
|
59
|
+
if (result.exitCode !== 0) {
|
|
60
|
+
return [];
|
|
61
|
+
}
|
|
62
|
+
return JSON.parse(result.stdout);
|
|
63
|
+
} catch {
|
|
64
|
+
return [];
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
async function claudePluginMarketplaceExists(name) {
|
|
68
|
+
const marketplaces = await claudePluginMarketplaceList();
|
|
69
|
+
return marketplaces.some((m) => m.name === name);
|
|
70
|
+
}
|
|
71
|
+
async function claudePluginMarketplaceAdd(githubRepo, name) {
|
|
72
|
+
const args = ["plugin", "marketplace", "add", githubRepo, "--name", name];
|
|
73
|
+
let result;
|
|
74
|
+
try {
|
|
75
|
+
result = await execCommand("claude", args, {});
|
|
76
|
+
} catch (err) {
|
|
77
|
+
throw new Error(
|
|
78
|
+
`Failed to add marketplace: ${err instanceof Error ? err.message : "Unknown error"}`
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
if (result.exitCode !== 0) {
|
|
82
|
+
const errorMessage = result.stderr || result.stdout || "Unknown error";
|
|
83
|
+
if (errorMessage.includes("already installed")) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
throw new Error(`Failed to add marketplace: ${errorMessage.trim()}`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
async function claudePluginUninstall(pluginName, scope, projectDir) {
|
|
90
|
+
const args = ["plugin", "uninstall", pluginName, "--scope", scope];
|
|
91
|
+
const result = await execCommand("claude", args, { cwd: projectDir });
|
|
92
|
+
if (result.exitCode !== 0) {
|
|
93
|
+
const errorMessage = result.stderr || result.stdout || "Unknown error";
|
|
94
|
+
if (errorMessage.includes("not installed") || errorMessage.includes("not found")) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
throw new Error(`Plugin uninstall failed: ${errorMessage.trim()}`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export {
|
|
102
|
+
claudePluginInstall,
|
|
103
|
+
isClaudeCLIAvailable,
|
|
104
|
+
claudePluginMarketplaceExists,
|
|
105
|
+
claudePluginMarketplaceAdd,
|
|
106
|
+
claudePluginUninstall
|
|
107
|
+
};
|
|
108
|
+
//# sourceMappingURL=chunk-M7YCPFIX.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli-v2/utils/exec.ts"],"sourcesContent":["import { spawn } from \"child_process\";\n\nexport interface ExecResult {\n stdout: string;\n stderr: string;\n exitCode: number;\n}\n\n/**\n * Execute a command and return the result\n */\nexport async function execCommand(\n command: string,\n args: string[],\n options?: { cwd?: string; env?: NodeJS.ProcessEnv },\n): Promise<ExecResult> {\n return new Promise((resolve, reject) => {\n const proc = spawn(command, args, {\n cwd: options?.cwd,\n env: { ...process.env, ...options?.env },\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n\n let stdout = \"\";\n let stderr = \"\";\n\n proc.stdout.on(\"data\", (data) => {\n stdout += data.toString();\n });\n\n proc.stderr.on(\"data\", (data) => {\n stderr += data.toString();\n });\n\n proc.on(\"close\", (code) => {\n resolve({\n stdout,\n stderr,\n exitCode: code ?? 1,\n });\n });\n\n proc.on(\"error\", (err) => {\n reject(err);\n });\n });\n}\n\n/**\n * Install a plugin using the native claude CLI\n */\nexport async function claudePluginInstall(\n pluginPath: string,\n scope: \"project\" | \"user\",\n projectDir: string,\n): Promise<void> {\n const args = [\"plugin\", \"install\", pluginPath, \"--scope\", scope];\n const result = await execCommand(\"claude\", args, { cwd: projectDir });\n\n if (result.exitCode !== 0) {\n const errorMessage = result.stderr || result.stdout || \"Unknown error\";\n throw new Error(`Plugin installation failed: ${errorMessage.trim()}`);\n }\n}\n\n/**\n * Check if the claude CLI is available\n */\nexport async function isClaudeCLIAvailable(): Promise<boolean> {\n try {\n const result = await execCommand(\"claude\", [\"--version\"], {});\n return result.exitCode === 0;\n } catch {\n return false;\n }\n}\n\nexport interface MarketplaceInfo {\n name: string;\n source: string;\n repo?: string;\n path?: string;\n}\n\n/**\n * List configured marketplaces in Claude Code\n */\nexport async function claudePluginMarketplaceList(): Promise<\n MarketplaceInfo[]\n> {\n try {\n const result = await execCommand(\n \"claude\",\n [\"plugin\", \"marketplace\", \"list\", \"--json\"],\n {},\n );\n\n if (result.exitCode !== 0) {\n return [];\n }\n\n return JSON.parse(result.stdout);\n } catch {\n // Returns empty array if claude CLI is not available or parsing fails\n return [];\n }\n}\n\n/**\n * Check if a marketplace with the given name exists\n */\nexport async function claudePluginMarketplaceExists(\n name: string,\n): Promise<boolean> {\n const marketplaces = await claudePluginMarketplaceList();\n return marketplaces.some((m) => m.name === name);\n}\n\n/**\n * Add a marketplace to Claude Code from a GitHub repository\n */\nexport async function claudePluginMarketplaceAdd(\n githubRepo: string,\n name: string,\n): Promise<void> {\n const args = [\"plugin\", \"marketplace\", \"add\", githubRepo, \"--name\", name];\n let result;\n try {\n result = await execCommand(\"claude\", args, {});\n } catch (err) {\n throw new Error(\n `Failed to add marketplace: ${err instanceof Error ? err.message : \"Unknown error\"}`,\n );\n }\n\n if (result.exitCode !== 0) {\n const errorMessage = result.stderr || result.stdout || \"Unknown error\";\n if (errorMessage.includes(\"already installed\")) {\n return;\n }\n throw new Error(`Failed to add marketplace: ${errorMessage.trim()}`);\n }\n}\n\n/**\n * Uninstall a plugin using the native claude CLI\n */\nexport async function claudePluginUninstall(\n pluginName: string,\n scope: \"project\" | \"user\",\n projectDir: string,\n): Promise<void> {\n const args = [\"plugin\", \"uninstall\", pluginName, \"--scope\", scope];\n const result = await execCommand(\"claude\", args, { cwd: projectDir });\n\n if (result.exitCode !== 0) {\n const errorMessage = result.stderr || result.stdout || \"Unknown error\";\n // Ignore \"not installed\" errors - plugin may already be removed\n if (\n errorMessage.includes(\"not installed\") ||\n errorMessage.includes(\"not found\")\n ) {\n return;\n }\n throw new Error(`Plugin uninstall failed: ${errorMessage.trim()}`);\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
fileExists,
|
|
4
|
+
glob,
|
|
5
|
+
readFile
|
|
6
|
+
} from "./chunk-MMDXNZPF.js";
|
|
7
|
+
import {
|
|
8
|
+
init_esm_shims
|
|
9
|
+
} from "./chunk-DHET7RCE.js";
|
|
10
|
+
|
|
11
|
+
// src/cli-v2/lib/versioning.ts
|
|
12
|
+
init_esm_shims();
|
|
13
|
+
import { createHash } from "crypto";
|
|
14
|
+
import path from "path";
|
|
15
|
+
import { stringify as stringifyYaml, parse as parseYaml } from "yaml";
|
|
16
|
+
var HASH_PREFIX_LENGTH = 7;
|
|
17
|
+
var HASHABLE_FILES = ["SKILL.md", "reference.md"];
|
|
18
|
+
var HASHABLE_DIRS = ["examples", "scripts"];
|
|
19
|
+
function hashString(content) {
|
|
20
|
+
const hash = createHash("sha256");
|
|
21
|
+
hash.update(content);
|
|
22
|
+
return hash.digest("hex").slice(0, HASH_PREFIX_LENGTH);
|
|
23
|
+
}
|
|
24
|
+
async function hashFile(filePath) {
|
|
25
|
+
const content = await readFile(filePath);
|
|
26
|
+
return hashString(content);
|
|
27
|
+
}
|
|
28
|
+
async function hashSkillFolder(skillPath) {
|
|
29
|
+
const contents = [];
|
|
30
|
+
for (const fileName of HASHABLE_FILES) {
|
|
31
|
+
const filePath = path.join(skillPath, fileName);
|
|
32
|
+
if (await fileExists(filePath)) {
|
|
33
|
+
const content = await readFile(filePath);
|
|
34
|
+
contents.push(`${fileName}:${content}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
for (const dirName of HASHABLE_DIRS) {
|
|
38
|
+
const dirPath = path.join(skillPath, dirName);
|
|
39
|
+
if (await fileExists(dirPath)) {
|
|
40
|
+
const files = await glob("**/*", dirPath);
|
|
41
|
+
for (const file of files.sort()) {
|
|
42
|
+
const filePath = path.join(dirPath, file);
|
|
43
|
+
const content = await readFile(filePath);
|
|
44
|
+
contents.push(`${dirName}/${file}:${content}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const combined = contents.join("\n---\n");
|
|
49
|
+
return hashString(combined);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export {
|
|
53
|
+
hashString,
|
|
54
|
+
hashFile,
|
|
55
|
+
hashSkillFolder
|
|
56
|
+
};
|
|
57
|
+
//# sourceMappingURL=chunk-MJSFR562.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli-v2/lib/versioning.ts"],"sourcesContent":["import { createHash } from \"crypto\";\nimport path from \"path\";\nimport { stringify as stringifyYaml, parse as parseYaml } from \"yaml\";\nimport { readFile, writeFile, glob, fileExists } from \"../utils/fs\";\nimport { verbose } from \"../utils/logger\";\n\nconst HASH_PREFIX_LENGTH = 7;\n\nconst METADATA_FILE_NAME = \"metadata.yaml\";\n\nconst HASHABLE_FILES = [\"SKILL.md\", \"reference.md\"];\n\nconst HASHABLE_DIRS = [\"examples\", \"scripts\"];\n\ninterface VersionedMetadata {\n version: number;\n content_hash?: string;\n updated?: string;\n [key: string]: unknown;\n}\n\nexport interface VersionCheckResult {\n skillPath: string;\n previousVersion: number;\n newVersion: number;\n previousHash: string | undefined;\n newHash: string;\n changed: boolean;\n}\n\nexport function getCurrentDate(): string {\n return new Date().toISOString().split(\"T\")[0];\n}\n\nexport function hashString(content: string): string {\n const hash = createHash(\"sha256\");\n hash.update(content);\n return hash.digest(\"hex\").slice(0, HASH_PREFIX_LENGTH);\n}\n\nexport async function hashFile(filePath: string): Promise<string> {\n const content = await readFile(filePath);\n return hashString(content);\n}\n\nexport async function hashSkillFolder(skillPath: string): Promise<string> {\n const contents: string[] = [];\n\n for (const fileName of HASHABLE_FILES) {\n const filePath = path.join(skillPath, fileName);\n if (await fileExists(filePath)) {\n const content = await readFile(filePath);\n contents.push(`${fileName}:${content}`);\n }\n }\n\n for (const dirName of HASHABLE_DIRS) {\n const dirPath = path.join(skillPath, dirName);\n if (await fileExists(dirPath)) {\n const files = await glob(\"**/*\", dirPath);\n for (const file of files.sort()) {\n const filePath = path.join(dirPath, file);\n const content = await readFile(filePath);\n contents.push(`${dirName}/${file}:${content}`);\n }\n }\n }\n\n const combined = contents.join(\"\\n---\\n\");\n return hashString(combined);\n}\n\nasync function readMetadata(\n skillPath: string,\n): Promise<{ metadata: VersionedMetadata; schemaComment: string }> {\n const metadataPath = path.join(skillPath, METADATA_FILE_NAME);\n const rawContent = await readFile(metadataPath);\n\n const lines = rawContent.split(\"\\n\");\n let schemaComment = \"\";\n let yamlContent = rawContent;\n\n if (lines[0]?.startsWith(\"# yaml-language-server:\")) {\n schemaComment = lines[0] + \"\\n\";\n yamlContent = lines.slice(1).join(\"\\n\");\n }\n\n const metadata = parseYaml(yamlContent) as VersionedMetadata;\n return { metadata, schemaComment };\n}\n\nasync function writeMetadata(\n skillPath: string,\n metadata: VersionedMetadata,\n schemaComment: string,\n): Promise<void> {\n const metadataPath = path.join(skillPath, METADATA_FILE_NAME);\n const yamlContent = stringifyYaml(metadata, { lineWidth: 0 });\n await writeFile(metadataPath, schemaComment + yamlContent);\n}\n\nexport async function versionSkill(\n skillPath: string,\n): Promise<VersionCheckResult> {\n const newHash = await hashSkillFolder(skillPath);\n\n const { metadata, schemaComment } = await readMetadata(skillPath);\n const previousVersion = metadata.version;\n const previousHash = metadata.content_hash;\n\n const changed = previousHash !== newHash;\n\n if (changed) {\n metadata.version = previousVersion + 1;\n metadata.content_hash = newHash;\n metadata.updated = getCurrentDate();\n\n await writeMetadata(skillPath, metadata, schemaComment);\n\n verbose(\n ` Version bumped: ${skillPath} (v${previousVersion} -> v${metadata.version})`,\n );\n }\n\n return {\n skillPath,\n previousVersion,\n newVersion: changed ? previousVersion + 1 : previousVersion,\n previousHash,\n newHash,\n changed,\n };\n}\n\nexport async function versionAllSkills(\n skillsDir: string,\n): Promise<VersionCheckResult[]> {\n const results: VersionCheckResult[] = [];\n\n const metadataFiles = await glob(\"**/metadata.yaml\", skillsDir);\n\n for (const metadataFile of metadataFiles) {\n const skillPath = path.join(skillsDir, path.dirname(metadataFile));\n\n try {\n const result = await versionSkill(skillPath);\n results.push(result);\n } catch (error) {\n console.warn(\n ` Warning: Failed to version skill at ${skillPath}: ${error}`,\n );\n }\n }\n\n return results;\n}\n\nexport function printVersionResults(results: VersionCheckResult[]): void {\n const changed = results.filter((r) => r.changed);\n const unchanged = results.filter((r) => !r.changed);\n\n if (changed.length > 0) {\n console.log(`\\n Version Updates:`);\n for (const result of changed) {\n const skillName = path.basename(result.skillPath);\n console.log(\n ` ✓ ${skillName}: v${result.previousVersion} -> v${result.newVersion}`,\n );\n }\n }\n\n console.log(\n `\\n Summary: ${changed.length} updated, ${unchanged.length} unchanged`,\n );\n}\n"],"mappings":";;;;;;;;;;;AAAA;AAAA,SAAS,kBAAkB;AAC3B,OAAO,UAAU;AACjB,SAAS,aAAa,eAAe,SAAS,iBAAiB;AAI/D,IAAM,qBAAqB;AAI3B,IAAM,iBAAiB,CAAC,YAAY,cAAc;AAElD,IAAM,gBAAgB,CAAC,YAAY,SAAS;AAsBrC,SAAS,WAAW,SAAyB;AAClD,QAAM,OAAO,WAAW,QAAQ;AAChC,OAAK,OAAO,OAAO;AACnB,SAAO,KAAK,OAAO,KAAK,EAAE,MAAM,GAAG,kBAAkB;AACvD;AAEA,eAAsB,SAAS,UAAmC;AAChE,QAAM,UAAU,MAAM,SAAS,QAAQ;AACvC,SAAO,WAAW,OAAO;AAC3B;AAEA,eAAsB,gBAAgB,WAAoC;AACxE,QAAM,WAAqB,CAAC;AAE5B,aAAW,YAAY,gBAAgB;AACrC,UAAM,WAAW,KAAK,KAAK,WAAW,QAAQ;AAC9C,QAAI,MAAM,WAAW,QAAQ,GAAG;AAC9B,YAAM,UAAU,MAAM,SAAS,QAAQ;AACvC,eAAS,KAAK,GAAG,QAAQ,IAAI,OAAO,EAAE;AAAA,IACxC;AAAA,EACF;AAEA,aAAW,WAAW,eAAe;AACnC,UAAM,UAAU,KAAK,KAAK,WAAW,OAAO;AAC5C,QAAI,MAAM,WAAW,OAAO,GAAG;AAC7B,YAAM,QAAQ,MAAM,KAAK,QAAQ,OAAO;AACxC,iBAAW,QAAQ,MAAM,KAAK,GAAG;AAC/B,cAAM,WAAW,KAAK,KAAK,SAAS,IAAI;AACxC,cAAM,UAAU,MAAM,SAAS,QAAQ;AACvC,iBAAS,KAAK,GAAG,OAAO,IAAI,IAAI,IAAI,OAAO,EAAE;AAAA,MAC/C;AAAA,IACF;AAAA,EACF;AAEA,QAAM,WAAW,SAAS,KAAK,SAAS;AACxC,SAAO,WAAW,QAAQ;AAC5B;","names":[]}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
init_esm_shims
|
|
4
|
+
} from "./chunk-DHET7RCE.js";
|
|
5
|
+
|
|
6
|
+
// src/cli-v2/utils/fs.ts
|
|
7
|
+
init_esm_shims();
|
|
8
|
+
import fs from "fs-extra";
|
|
9
|
+
import fg from "fast-glob";
|
|
10
|
+
import path from "path";
|
|
11
|
+
async function readFile(filePath) {
|
|
12
|
+
return fs.readFile(filePath, "utf-8");
|
|
13
|
+
}
|
|
14
|
+
async function readFileOptional(filePath, fallback = "") {
|
|
15
|
+
try {
|
|
16
|
+
return await fs.readFile(filePath, "utf-8");
|
|
17
|
+
} catch {
|
|
18
|
+
return fallback;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
async function fileExists(filePath) {
|
|
22
|
+
return fs.pathExists(filePath);
|
|
23
|
+
}
|
|
24
|
+
async function directoryExists(dirPath) {
|
|
25
|
+
try {
|
|
26
|
+
const stat = await fs.stat(dirPath);
|
|
27
|
+
return stat.isDirectory();
|
|
28
|
+
} catch {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
async function listDirectories(dirPath) {
|
|
33
|
+
try {
|
|
34
|
+
const entries = await fs.readdir(dirPath, { withFileTypes: true });
|
|
35
|
+
return entries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
36
|
+
} catch {
|
|
37
|
+
return [];
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
async function glob(pattern, cwd) {
|
|
41
|
+
return fg(pattern, { cwd, onlyFiles: true });
|
|
42
|
+
}
|
|
43
|
+
async function writeFile(filePath, content) {
|
|
44
|
+
await fs.ensureDir(path.dirname(filePath));
|
|
45
|
+
await fs.writeFile(filePath, content, "utf-8");
|
|
46
|
+
}
|
|
47
|
+
async function ensureDir(dirPath) {
|
|
48
|
+
await fs.ensureDir(dirPath);
|
|
49
|
+
}
|
|
50
|
+
async function remove(filePath) {
|
|
51
|
+
await fs.remove(filePath);
|
|
52
|
+
}
|
|
53
|
+
async function copy(src, dest) {
|
|
54
|
+
await fs.copy(src, dest);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export {
|
|
58
|
+
readFile,
|
|
59
|
+
readFileOptional,
|
|
60
|
+
fileExists,
|
|
61
|
+
directoryExists,
|
|
62
|
+
listDirectories,
|
|
63
|
+
glob,
|
|
64
|
+
writeFile,
|
|
65
|
+
ensureDir,
|
|
66
|
+
remove,
|
|
67
|
+
copy
|
|
68
|
+
};
|
|
69
|
+
//# sourceMappingURL=chunk-MMDXNZPF.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli-v2/utils/fs.ts"],"sourcesContent":["import fs from \"fs-extra\";\nimport fg from \"fast-glob\";\nimport path from \"path\";\n\nexport async function readFile(filePath: string): Promise<string> {\n return fs.readFile(filePath, \"utf-8\");\n}\n\nexport async function readFileOptional(\n filePath: string,\n fallback = \"\",\n): Promise<string> {\n try {\n return await fs.readFile(filePath, \"utf-8\");\n } catch {\n return fallback;\n }\n}\n\nexport async function fileExists(filePath: string): Promise<boolean> {\n return fs.pathExists(filePath);\n}\n\nexport async function directoryExists(dirPath: string): Promise<boolean> {\n try {\n const stat = await fs.stat(dirPath);\n return stat.isDirectory();\n } catch {\n return false;\n }\n}\n\nexport async function listDirectories(dirPath: string): Promise<string[]> {\n try {\n const entries = await fs.readdir(dirPath, { withFileTypes: true });\n return entries.filter((e) => e.isDirectory()).map((e) => e.name);\n } catch {\n return [];\n }\n}\n\nexport async function glob(pattern: string, cwd: string): Promise<string[]> {\n return fg(pattern, { cwd, onlyFiles: true });\n}\n\nexport async function writeFile(\n filePath: string,\n content: string,\n): Promise<void> {\n await fs.ensureDir(path.dirname(filePath));\n await fs.writeFile(filePath, content, \"utf-8\");\n}\n\nexport async function ensureDir(dirPath: string): Promise<void> {\n await fs.ensureDir(dirPath);\n}\n\nexport async function remove(filePath: string): Promise<void> {\n await fs.remove(filePath);\n}\n\nexport async function copy(src: string, dest: string): Promise<void> {\n await fs.copy(src, dest);\n}\n"],"mappings":";;;;;;AAAA;AAAA,OAAO,QAAQ;AACf,OAAO,QAAQ;AACf,OAAO,UAAU;AAEjB,eAAsB,SAAS,UAAmC;AAChE,SAAO,GAAG,SAAS,UAAU,OAAO;AACtC;AAEA,eAAsB,iBACpB,UACA,WAAW,IACM;AACjB,MAAI;AACF,WAAO,MAAM,GAAG,SAAS,UAAU,OAAO;AAAA,EAC5C,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,WAAW,UAAoC;AACnE,SAAO,GAAG,WAAW,QAAQ;AAC/B;AAEA,eAAsB,gBAAgB,SAAmC;AACvE,MAAI;AACF,UAAM,OAAO,MAAM,GAAG,KAAK,OAAO;AAClC,WAAO,KAAK,YAAY;AAAA,EAC1B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,gBAAgB,SAAoC;AACxE,MAAI;AACF,UAAM,UAAU,MAAM,GAAG,QAAQ,SAAS,EAAE,eAAe,KAAK,CAAC;AACjE,WAAO,QAAQ,OAAO,CAAC,MAAM,EAAE,YAAY,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI;AAAA,EACjE,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAEA,eAAsB,KAAK,SAAiB,KAAgC;AAC1E,SAAO,GAAG,SAAS,EAAE,KAAK,WAAW,KAAK,CAAC;AAC7C;AAEA,eAAsB,UACpB,UACA,SACe;AACf,QAAM,GAAG,UAAU,KAAK,QAAQ,QAAQ,CAAC;AACzC,QAAM,GAAG,UAAU,UAAU,SAAS,OAAO;AAC/C;AAEA,eAAsB,UAAU,SAAgC;AAC9D,QAAM,GAAG,UAAU,OAAO;AAC5B;AAEA,eAAsB,OAAO,UAAiC;AAC5D,QAAM,GAAG,OAAO,QAAQ;AAC1B;AAEA,eAAsB,KAAK,KAAa,MAA6B;AACnE,QAAM,GAAG,KAAK,KAAK,IAAI;AACzB;","names":[]}
|