diff --git a/.codex/superpowers-codex b/.codex/superpowers-codex index 0066977a1..8d493a63f 100755 --- a/.codex/superpowers-codex +++ b/.codex/superpowers-codex @@ -1,388 +1,4 @@ #!/usr/bin/env node -const fs = require('fs'); -const path = require('path'); -const os = require('os'); -const { execSync } = require('child_process'); - -// Paths -const homeDir = os.homedir(); -const superpowersSkillsDir = path.join(homeDir, '.codex', 'superpowers', 'skills'); -const personalSkillsDir = path.join(homeDir, '.codex', 'skills'); -const bootstrapFile = path.join(homeDir, '.codex', 'superpowers', '.codex', 'superpowers-bootstrap.md'); -const superpowersRepoDir = path.join(homeDir, '.codex', 'superpowers'); - -// Utility functions -function checkForUpdates() { - try { - // Quick check with 3 second timeout to avoid delays if network is down - const output = execSync('git fetch origin && git status --porcelain=v1 --branch', { - cwd: superpowersRepoDir, - timeout: 3000, - encoding: 'utf8', - stdio: 'pipe' - }); - - // Parse git status output to see if we're behind - const statusLines = output.split('\n'); - for (const line of statusLines) { - if (line.startsWith('## ') && line.includes('[behind ')) { - return true; // We're behind remote - } - } - return false; // Up to date - } catch (error) { - // Network down, git error, timeout, etc. - don't block bootstrap - return false; - } -} - -function extractFrontmatter(filePath) { - try { - const content = fs.readFileSync(filePath, 'utf8'); - const lines = content.split('\n'); - - let inFrontmatter = false; - let name = ''; - let description = ''; - let whenToUse = ''; - - for (const line of lines) { - if (line.trim() === '---') { - if (inFrontmatter) break; - inFrontmatter = true; - continue; - } - - if (inFrontmatter) { - const match = line.match(/^(\w+):\s*(.*)$/); - if (match) { - const [, key, value] = match; - switch (key) { - case 'name': name = value.trim(); break; - case 'description': description = value.trim(); break; - case 'when_to_use': whenToUse = value.trim(); break; - } - } - } - } - - return { name, description, whenToUse }; - } catch (error) { - return { name: '', description: '', whenToUse: '' }; - } -} - -function printSkill(skillPath, sourceType) { - const skillFile = path.join(skillPath, 'SKILL.md'); - const relPath = sourceType === 'personal' - ? path.relative(personalSkillsDir, skillPath) - : path.relative(superpowersSkillsDir, skillPath); - - // Print skill name with namespace - if (sourceType === 'personal') { - console.log(relPath.replace(/\\/g, '/')); // Personal skills are not namespaced - } else { - console.log(`superpowers:${relPath.replace(/\\/g, '/')}`); // Superpowers skills get superpowers namespace - } - - // Extract and print metadata - const { name, description, whenToUse } = extractFrontmatter(skillFile); - - if (description) console.log(` ${description}`); - if (whenToUse) console.log(` When to use: ${whenToUse}`); - console.log(''); -} - -function findSkillsInDir(dir, sourceType, maxDepth = 1) { - const skills = []; - - if (!fs.existsSync(dir)) return skills; - - function searchDir(currentDir, currentDepth) { - if (currentDepth > maxDepth) return; - - try { - const entries = fs.readdirSync(currentDir, { withFileTypes: true }); - - for (const entry of entries) { - if (entry.isDirectory()) { - const skillDir = path.join(currentDir, entry.name); - const skillFile = path.join(skillDir, 'SKILL.md'); - - if (fs.existsSync(skillFile)) { - skills.push(skillDir); - } - - // For personal skills, search deeper (category/skill structure) - if (sourceType === 'personal' && currentDepth < maxDepth) { - searchDir(skillDir, currentDepth + 1); - } - } - } - } catch (error) { - // Ignore permission errors or other issues - } - } - - searchDir(dir, 0); - return skills; -} - -// Commands -function runFindSkills() { - console.log('Available skills:'); - console.log('=================='); - console.log(''); - - const foundSkills = new Set(); - - // Find personal skills first (these take precedence) - const personalSkills = findSkillsInDir(personalSkillsDir, 'personal', 2); - for (const skillPath of personalSkills) { - const relPath = path.relative(personalSkillsDir, skillPath); - foundSkills.add(relPath); - printSkill(skillPath, 'personal'); - } - - // Find superpowers skills (only if not already found in personal) - const superpowersSkills = findSkillsInDir(superpowersSkillsDir, 'superpowers', 1); - for (const skillPath of superpowersSkills) { - const relPath = path.relative(superpowersSkillsDir, skillPath); - if (!foundSkills.has(relPath)) { - printSkill(skillPath, 'superpowers'); - } - } - - console.log('Usage:'); - console.log(' superpowers-codex use-skill # Load a specific skill'); - console.log(''); - console.log('Skill naming:'); - console.log(' Superpowers skills: superpowers:skill-name (from ~/.codex/superpowers/skills/)'); - console.log(' Personal skills: skill-name (from ~/.codex/skills/)'); - console.log(' Personal skills override superpowers skills when names match.'); - console.log(''); - console.log('Note: All skills are disclosed at session start via bootstrap.'); -} - -function runBootstrap() { - console.log('# Superpowers Bootstrap for Codex'); - console.log('# ================================'); - console.log(''); - - // Check for updates (with timeout protection) - if (checkForUpdates()) { - console.log('## Update Available'); - console.log(''); - console.log('⚠️ Your superpowers installation is behind the latest version.'); - console.log('To update, run: `cd ~/.codex/superpowers && git pull`'); - console.log(''); - console.log('---'); - console.log(''); - } - - // Show the bootstrap instructions - if (fs.existsSync(bootstrapFile)) { - console.log('## Bootstrap Instructions:'); - console.log(''); - try { - const content = fs.readFileSync(bootstrapFile, 'utf8'); - console.log(content); - } catch (error) { - console.log(`Error reading bootstrap file: ${error.message}`); - } - console.log(''); - console.log('---'); - console.log(''); - } - - // Run find-skills to show available skills - console.log('## Available Skills:'); - console.log(''); - runFindSkills(); - - console.log(''); - console.log('---'); - console.log(''); - - // Load the using-superpowers skill automatically - console.log('## Auto-loading superpowers:using-superpowers skill:'); - console.log(''); - runUseSkill('superpowers:using-superpowers'); - - console.log(''); - console.log('---'); - console.log(''); - console.log('# Bootstrap Complete!'); - console.log('# You now have access to all superpowers skills.'); - console.log('# Use "superpowers-codex use-skill " to load and apply skills.'); - console.log('# Remember: If a skill applies to your task, you MUST use it!'); -} - -function runUseSkill(skillName) { - if (!skillName) { - console.log('Usage: superpowers-codex use-skill '); - console.log('Examples:'); - console.log(' superpowers-codex use-skill superpowers:brainstorming # Load superpowers skill'); - console.log(' superpowers-codex use-skill brainstorming # Load personal skill (or superpowers if not found)'); - console.log(' superpowers-codex use-skill my-custom-skill # Load personal skill'); - return; - } - - // Handle namespaced skill names - let actualSkillPath; - let forceSuperpowers = false; - - if (skillName.startsWith('superpowers:')) { - // Remove the superpowers: namespace prefix - actualSkillPath = skillName.substring('superpowers:'.length); - forceSuperpowers = true; - } else { - actualSkillPath = skillName; - } - - // Remove "skills/" prefix if present - if (actualSkillPath.startsWith('skills/')) { - actualSkillPath = actualSkillPath.substring('skills/'.length); - } - - // Function to find skill file - function findSkillFile(searchPath) { - // Check for exact match with SKILL.md - const skillMdPath = path.join(searchPath, 'SKILL.md'); - if (fs.existsSync(skillMdPath)) { - return skillMdPath; - } - - // Check for direct SKILL.md file - if (searchPath.endsWith('SKILL.md') && fs.existsSync(searchPath)) { - return searchPath; - } - - return null; - } - - let skillFile = null; - - // If superpowers: namespace was used, only check superpowers skills - if (forceSuperpowers) { - if (fs.existsSync(superpowersSkillsDir)) { - const superpowersPath = path.join(superpowersSkillsDir, actualSkillPath); - skillFile = findSkillFile(superpowersPath); - } - } else { - // First check personal skills directory (takes precedence) - if (fs.existsSync(personalSkillsDir)) { - const personalPath = path.join(personalSkillsDir, actualSkillPath); - skillFile = findSkillFile(personalPath); - if (skillFile) { - console.log(`# Loading personal skill: ${actualSkillPath}`); - console.log(`# Source: ${skillFile}`); - console.log(''); - } - } - - // If not found in personal, check superpowers skills - if (!skillFile && fs.existsSync(superpowersSkillsDir)) { - const superpowersPath = path.join(superpowersSkillsDir, actualSkillPath); - skillFile = findSkillFile(superpowersPath); - if (skillFile) { - console.log(`# Loading superpowers skill: superpowers:${actualSkillPath}`); - console.log(`# Source: ${skillFile}`); - console.log(''); - } - } - } - - // If still not found, error - if (!skillFile) { - console.log(`Error: Skill not found: ${actualSkillPath}`); - console.log(''); - console.log('Available skills:'); - runFindSkills(); - return; - } - - // Extract frontmatter and content - let content, frontmatter; - try { - const fullContent = fs.readFileSync(skillFile, 'utf8'); - const { name, description, whenToUse } = extractFrontmatter(skillFile); - - // Extract just the content after frontmatter - const lines = fullContent.split('\n'); - let inFrontmatter = false; - let frontmatterEnded = false; - const contentLines = []; - - for (const line of lines) { - if (line.trim() === '---') { - if (inFrontmatter) { - frontmatterEnded = true; - continue; - } - inFrontmatter = true; - continue; - } - - if (frontmatterEnded || !inFrontmatter) { - contentLines.push(line); - } - } - - content = contentLines.join('\n').trim(); - frontmatter = { name, description, whenToUse }; - } catch (error) { - console.log(`Error reading skill file: ${error.message}`); - return; - } - - // Display skill header with clean info - const displayName = forceSuperpowers ? `superpowers:${actualSkillPath}` : - (skillFile.includes(personalSkillsDir) ? actualSkillPath : `superpowers:${actualSkillPath}`); - - const skillDirectory = path.dirname(skillFile); - - console.log(`# ${frontmatter.name || displayName}`); - if (frontmatter.description) { - console.log(`# ${frontmatter.description}`); - } - if (frontmatter.whenToUse) { - console.log(`# When to use: ${frontmatter.whenToUse}`); - } - console.log(`# Supporting tools and docs are in ${skillDirectory}`); - console.log('# ============================================'); - console.log(''); - - // Display the skill content (without frontmatter) - console.log(content); - -} - -// Main CLI -const command = process.argv[2]; -const arg = process.argv[3]; - -switch (command) { - case 'bootstrap': - runBootstrap(); - break; - case 'use-skill': - runUseSkill(arg); - break; - case 'find-skills': - runFindSkills(); - break; - default: - console.log('Superpowers for Codex'); - console.log('Usage:'); - console.log(' superpowers-codex bootstrap # Run complete bootstrap with all skills'); - console.log(' superpowers-codex use-skill # Load a specific skill'); - console.log(' superpowers-codex find-skills # List all available skills'); - console.log(''); - console.log('Examples:'); - console.log(' superpowers-codex bootstrap'); - console.log(' superpowers-codex use-skill superpowers:brainstorming'); - console.log(' superpowers-codex use-skill my-custom-skill'); - break; -} \ No newline at end of file +// Wrapper script for superpowers-codex that delegates to the shared bootstrap code +require('../bootstrap/superpowers-bootstrap.js'); \ No newline at end of file diff --git a/.opencode/INSTALL.md b/.opencode/INSTALL.md new file mode 100644 index 000000000..6ad334b71 --- /dev/null +++ b/.opencode/INSTALL.md @@ -0,0 +1,35 @@ +# Installing Superpowers for opencode + +Quick setup to enable superpowers skills in opencode. + +## Installation + +1. **Clone superpowers repository**: + ```bash + mkdir -p ~/.opencode/superpowers + cd ~/.opencode/superpowers + git clone https://github.com/obra/superpowers.git . + ``` + +2. **Create personal skills directory**: + ```bash + mkdir -p ~/.opencode/skills + ``` + +3. **Update ~/.opencode/AGENTS.md** to include this superpowers section: + ```markdown + ## Superpowers System + + + You have superpowers. Superpowers teach you new skills and capabilities. RIGHT NOW run: `~/.opencode/superpowers/.opencode/superpowers-opencode bootstrap` and follow the instructions it returns. + + ``` + +## Verification + +Test the installation: +```bash +~/.opencode/superpowers/.opencode/superpowers-opencode bootstrap +``` + +You should see skill listings and bootstrap instructions. The system is now ready for use. \ No newline at end of file diff --git a/.opencode/superpowers-bootstrap.md b/.opencode/superpowers-bootstrap.md new file mode 100644 index 000000000..36d01c87b --- /dev/null +++ b/.opencode/superpowers-bootstrap.md @@ -0,0 +1,32 @@ +# Superpowers Bootstrap for opencode + + +You have superpowers. + +**Tool for running skills:** +- `~/.opencode/superpowers/.opencode/superpowers-opencode use-skill ` + +**Tool Mapping for opencode:** +When skills reference tools you don't have, substitute your equivalent tools: +- `Task` tool with subagents → Use the Task tool with subagent_type: "general" to invoke subagents for testing and research +- `Skill` tool → `~/.opencode/superpowers/.opencode/superpowers-opencode use-skill` command (already available) +- `Read`, `Write`, `Edit`, `Bash` → Use your native tools with similar functions + +**Skills naming:** +- Superpowers skills: `superpowers:skill-name` (from ~/.opencode/superpowers/skills/) +- Personal skills: `skill-name` (from ~/.opencode/skills/) +- Personal skills override superpowers skills when names match + +**Critical Rules:** +- Before ANY task, review the skills list (shown below) +- If a relevant skill exists, you MUST use `~/.opencode/superpowers/.opencode/superpowers-opencode use-skill` to load it +- Announce: "I've read the [Skill Name] skill and I'm using it to [purpose]" +- Skills with checklists require `update_plan` todos for each item +- NEVER skip mandatory workflows (brainstorming before coding, TDD, systematic debugging) + +**Skills location:** +- Superpowers skills: ~/.opencode/superpowers/skills/ +- Personal skills: ~/.opencode/skills/ (override superpowers when names match) + +IF A SKILL APPLIES TO YOUR TASK, YOU DO NOT HAVE A CHOICE. YOU MUST USE IT. + \ No newline at end of file diff --git a/.opencode/superpowers-opencode b/.opencode/superpowers-opencode new file mode 100755 index 000000000..3f1b52821 --- /dev/null +++ b/.opencode/superpowers-opencode @@ -0,0 +1,4 @@ +#!/usr/bin/env node + +// Wrapper script for superpowers-opencode that delegates to the shared bootstrap code +require('../bootstrap/superpowers-bootstrap.js'); \ No newline at end of file diff --git a/bootstrap/superpowers-bootstrap.js b/bootstrap/superpowers-bootstrap.js new file mode 100755 index 000000000..bc4ba88e4 --- /dev/null +++ b/bootstrap/superpowers-bootstrap.js @@ -0,0 +1,404 @@ +#!/usr/bin/env node + +const fs = require('fs'); +const path = require('path'); +const os = require('os'); +const { execSync } = require('child_process'); + +// Auto-detect context from parent directory +function detectContext() { + // Get directory containing the wrapper script + const wrapperScript = process.argv[1]; + const wrapperDir = path.dirname(path.resolve(wrapperScript)); + const context = path.basename(wrapperDir); + + // Validate it's a valid context directory (starts with dot) + if (!context.startsWith('.')) { + throw new Error(`Invalid context directory: ${context}. Expected directory starting with '.'`); + } + + return context.substring(1); // Remove dot to get context name +} + +// Set up paths based on detected context +const context = detectContext(); +const homeDir = os.homedir(); +const superpowersSkillsDir = path.join(homeDir, `.${context}`, 'superpowers', 'skills'); +const personalSkillsDir = path.join(homeDir, `.${context}`, 'skills'); +const bootstrapFile = path.join(homeDir, `.${context}`, 'superpowers', `.${context}`, 'superpowers-bootstrap.md'); +const superpowersRepoDir = path.join(homeDir, `.${context}`, 'superpowers'); + +// Utility functions +function checkForUpdates() { + try { + // Quick check with 3 second timeout to avoid delays if network is down + const output = execSync('git fetch origin && git status --porcelain=v1 --branch', { + cwd: superpowersRepoDir, + timeout: 3000, + encoding: 'utf8', + stdio: 'pipe' + }); + + // Parse git status output to see if we're behind + const statusLines = output.split('\n'); + for (const line of statusLines) { + if (line.startsWith('## ') && line.includes('[behind ')) { + return true; // We're behind remote + } + } + return false; // Up to date + } catch (error) { + // Network down, git error, timeout, etc. - don't block bootstrap + return false; + } +} + +function extractFrontmatter(filePath) { + try { + const content = fs.readFileSync(filePath, 'utf8'); + const lines = content.split('\n'); + + let inFrontmatter = false; + let name = ''; + let description = ''; + let whenToUse = ''; + + for (const line of lines) { + if (line.trim() === '---') { + if (inFrontmatter) break; + inFrontmatter = true; + continue; + } + + if (inFrontmatter) { + const match = line.match(/^(\w+):\s*(.*)$/); + if (match) { + const [, key, value] = match; + switch (key) { + case 'name': name = value.trim(); break; + case 'description': description = value.trim(); break; + case 'when_to_use': whenToUse = value.trim(); break; + } + } + } + } + + return { name, description, whenToUse }; + } catch (error) { + return { name: '', description: '', whenToUse: '' }; + } +} + +function printSkill(skillPath, sourceType) { + const skillFile = path.join(skillPath, 'SKILL.md'); + const relPath = sourceType === 'personal' + ? path.relative(personalSkillsDir, skillPath) + : path.relative(superpowersSkillsDir, skillPath); + + // Print skill name with namespace + if (sourceType === 'personal') { + console.log(relPath.replace(/\\/g, '/')); // Personal skills are not namespaced + } else { + console.log(`superpowers:${relPath.replace(/\\/g, '/')}`); // Superpowers skills get superpowers namespace + } + + // Extract and print metadata + const { name, description, whenToUse } = extractFrontmatter(skillFile); + + if (description) console.log(` ${description}`); + if (whenToUse) console.log(` When to use: ${whenToUse}`); + console.log(''); +} + +function findSkillsInDir(dir, sourceType, maxDepth = 1) { + const skills = []; + + if (!fs.existsSync(dir)) return skills; + + function searchDir(currentDir, currentDepth) { + if (currentDepth > maxDepth) return; + + try { + const entries = fs.readdirSync(currentDir, { withFileTypes: true }); + + for (const entry of entries) { + if (entry.isDirectory()) { + const skillDir = path.join(currentDir, entry.name); + const skillFile = path.join(skillDir, 'SKILL.md'); + + if (fs.existsSync(skillFile)) { + skills.push(skillDir); + } + + // For personal skills, search deeper (category/skill structure) + if (sourceType === 'personal' && currentDepth < maxDepth) { + searchDir(skillDir, currentDepth + 1); + } + } + } + } catch (error) { + // Ignore permission errors or other issues + } + } + + searchDir(dir, 0); + return skills; +} + +// Commands +function runFindSkills() { + console.log('Available skills:'); + console.log('=================='); + console.log(''); + + const foundSkills = new Set(); + + // Find personal skills first (these take precedence) + const personalSkills = findSkillsInDir(personalSkillsDir, 'personal', 2); + for (const skillPath of personalSkills) { + const relPath = path.relative(personalSkillsDir, skillPath); + foundSkills.add(relPath); + printSkill(skillPath, 'personal'); + } + + // Find superpowers skills (only if not already found in personal) + const superpowersSkills = findSkillsInDir(superpowersSkillsDir, 'superpowers', 1); + for (const skillPath of superpowersSkills) { + const relPath = path.relative(superpowersSkillsDir, skillPath); + if (!foundSkills.has(relPath)) { + printSkill(skillPath, 'superpowers'); + } + } + + console.log('Usage:'); + console.log(` superpowers-${context} use-skill # Load a specific skill`); + console.log(''); + console.log('Skill naming:'); + console.log(` Superpowers skills: superpowers:skill-name (from ~/.${context}/superpowers/skills/)`); + console.log(` Personal skills: skill-name (from ~/.${context}/skills/)`); + console.log(' Personal skills override superpowers skills when names match.'); + console.log(''); + console.log('Note: All skills are disclosed at session start via bootstrap.'); +} + +function runBootstrap() { + console.log(`# Superpowers Bootstrap for ${context}`); + console.log('# ================================'); + console.log(''); + + // Check for updates (with timeout protection) + if (checkForUpdates()) { + console.log('## Update Available'); + console.log(''); + console.log('⚠️ Your superpowers installation is behind the latest version.'); + console.log(`To update, run: \`cd ~/.${context}/superpowers && git pull\``); + console.log(''); + console.log('---'); + console.log(''); + } + + // Show the bootstrap instructions + if (fs.existsSync(bootstrapFile)) { + console.log('## Bootstrap Instructions:'); + console.log(''); + try { + const content = fs.readFileSync(bootstrapFile, 'utf8'); + console.log(content); + } catch (error) { + console.log(`Error reading bootstrap file: ${error.message}`); + } + console.log(''); + console.log('---'); + console.log(''); + } + + // Run find-skills to show available skills + console.log('## Available Skills:'); + console.log(''); + runFindSkills(); + + console.log(''); + console.log('---'); + console.log(''); + + // Load the using-superpowers skill automatically + console.log('## Auto-loading superpowers:using-superpowers skill:'); + console.log(''); + runUseSkill('superpowers:using-superpowers'); + + console.log(''); + console.log('---'); + console.log(''); + console.log('# Bootstrap Complete!'); + console.log('# You now have access to all superpowers skills.'); + console.log(`# Use "superpowers-${context} use-skill " to load and apply skills.`); + console.log('# Remember: If a skill applies to your task, you MUST use it!'); +} + +function runUseSkill(skillName) { + if (!skillName) { + console.log(`Usage: superpowers-${context} use-skill `); + console.log('Examples:'); + console.log(` superpowers-${context} use-skill superpowers:brainstorming # Load superpowers skill`); + console.log(` superpowers-${context} use-skill brainstorming # Load personal skill (or superpowers if not found)`); + console.log(` superpowers-${context} use-skill my-custom-skill # Load personal skill`); + return; + } + + // Handle namespaced skill names + let actualSkillPath; + let forceSuperpowers = false; + + if (skillName.startsWith('superpowers:')) { + // Remove the superpowers: namespace prefix + actualSkillPath = skillName.substring('superpowers:'.length); + forceSuperpowers = true; + } else { + actualSkillPath = skillName; + } + + // Remove "skills/" prefix if present + if (actualSkillPath.startsWith('skills/')) { + actualSkillPath = actualSkillPath.substring('skills/'.length); + } + + // Function to find skill file + function findSkillFile(searchPath) { + // Check for exact match with SKILL.md + const skillMdPath = path.join(searchPath, 'SKILL.md'); + if (fs.existsSync(skillMdPath)) { + return skillMdPath; + } + + // Check for direct SKILL.md file + if (searchPath.endsWith('SKILL.md') && fs.existsSync(searchPath)) { + return searchPath; + } + + return null; + } + + let skillFile = null; + + // If superpowers: namespace was used, only check superpowers skills + if (forceSuperpowers) { + if (fs.existsSync(superpowersSkillsDir)) { + const superpowersPath = path.join(superpowersSkillsDir, actualSkillPath); + skillFile = findSkillFile(superpowersPath); + } + } else { + // First check personal skills directory (takes precedence) + if (fs.existsSync(personalSkillsDir)) { + const personalPath = path.join(personalSkillsDir, actualSkillPath); + skillFile = findSkillFile(personalPath); + if (skillFile) { + console.log(`# Loading personal skill: ${actualSkillPath}`); + console.log(`# Source: ${skillFile}`); + console.log(''); + } + } + + // If not found in personal, check superpowers skills + if (!skillFile && fs.existsSync(superpowersSkillsDir)) { + const superpowersPath = path.join(superpowersSkillsDir, actualSkillPath); + skillFile = findSkillFile(superpowersPath); + if (skillFile) { + console.log(`# Loading superpowers skill: superpowers:${actualSkillPath}`); + console.log(`# Source: ${skillFile}`); + console.log(''); + } + } + } + + // If still not found, error + if (!skillFile) { + console.log(`Error: Skill not found: ${actualSkillPath}`); + console.log(''); + console.log('Available skills:'); + runFindSkills(); + return; + } + + // Extract frontmatter and content + let content, frontmatter; + try { + const fullContent = fs.readFileSync(skillFile, 'utf8'); + const { name, description, whenToUse } = extractFrontmatter(skillFile); + + // Extract just the content after frontmatter + const lines = fullContent.split('\n'); + let inFrontmatter = false; + let frontmatterEnded = false; + const contentLines = []; + + for (const line of lines) { + if (line.trim() === '---') { + if (inFrontmatter) { + frontmatterEnded = true; + continue; + } + inFrontmatter = true; + continue; + } + + if (frontmatterEnded || !inFrontmatter) { + contentLines.push(line); + } + } + + content = contentLines.join('\n').trim(); + frontmatter = { name, description, whenToUse }; + } catch (error) { + console.log(`Error reading skill file: ${error.message}`); + return; + } + + // Display skill header with clean info + const displayName = forceSuperpowers ? `superpowers:${actualSkillPath}` : + (skillFile.includes(personalSkillsDir) ? actualSkillPath : `superpowers:${actualSkillPath}`); + + const skillDirectory = path.dirname(skillFile); + + console.log(`# ${frontmatter.name || displayName}`); + if (frontmatter.description) { + console.log(`# ${frontmatter.description}`); + } + if (frontmatter.whenToUse) { + console.log(`# When to use: ${frontmatter.whenToUse}`); + } + console.log(`# Supporting tools and docs are in ${skillDirectory}`); + console.log('# ============================================'); + console.log(''); + + // Display the skill content (without frontmatter) + console.log(content); + +} + +// Main CLI +const command = process.argv[2]; +const arg = process.argv[3]; + +switch (command) { + case 'bootstrap': + runBootstrap(); + break; + case 'use-skill': + runUseSkill(arg); + break; + case 'find-skills': + runFindSkills(); + break; + default: + console.log(`Superpowers for ${context}`); + console.log('Usage:'); + console.log(` superpowers-${context} bootstrap # Run complete bootstrap with all skills`); + console.log(` superpowers-${context} use-skill # Load a specific skill`); + console.log(` superpowers-${context} find-skills # List all available skills`); + console.log(''); + console.log('Examples:'); + console.log(` superpowers-${context} bootstrap`); + console.log(` superpowers-${context} use-skill superpowers:brainstorming`); + console.log(` superpowers-${context} use-skill my-custom-skill`); + break; +} \ No newline at end of file