UNPKG

@lsendel/claude-agents

Version:

Supercharge Claude Code with specialized AI sub-agents for code review, testing, debugging, documentation & more. Now with process & standards management! Easy CLI tool to install, manage & create custom AI agents for enhanced development workflow

132 lines (110 loc) 3.48 kB
import yaml from 'yaml'; /** * Parse YAML frontmatter with support for Claude Code format * Claude Code uses unquoted long descriptions with \n escape sequences */ export function parseYamlFrontmatter(yamlContent) { try { // First try standard YAML parsing return yaml.parse(yamlContent); } catch (e) { // If standard parsing fails, try Claude Code format return parseClaudeCodeFormat(yamlContent); } } /** * Parse Claude Code's specific YAML format * Handles unquoted multi-line descriptions with \n */ function parseClaudeCodeFormat(yamlContent) { const result = {}; const lines = yamlContent.split('\n'); let currentKey = null; let currentValue = ''; let inMultilineValue = false; for (let i = 0; i < lines.length; i++) { const line = lines[i]; // Skip empty lines if (!line.trim()) continue; // Check if this is a new key-value pair const keyMatch = /^(\w+):\s*(.*)$/.exec(line); if (keyMatch && !inMultilineValue) { // Save previous key-value if exists if (currentKey) { result[currentKey] = processValue(currentValue.trim()); } currentKey = keyMatch[1]; currentValue = keyMatch[2]; // Check if this is a multi-line value (contains \n or very long) if ( currentKey === 'description' && (currentValue.includes('\\n') || currentValue.length > 100) ) { inMultilineValue = true; } else { // Single line value - save it immediately result[currentKey] = processValue(currentValue); currentKey = null; currentValue = ''; } } else if (inMultilineValue) { // Check if this line starts a new key (not part of description) const nextKeyMatch = /^(name|tools|color|version|author|tags):\s*/.exec( line, ); if (nextKeyMatch) { // End of multi-line value result[currentKey] = processValue(currentValue.trim()); inMultilineValue = false; // Process this line as a new key i--; // Reprocess this line currentKey = null; currentValue = ''; } else { // Continue multi-line value currentValue += ' ' + line.trim(); } } } // Save last key-value if exists if (currentKey) { result[currentKey] = processValue(currentValue.trim()); } return result; } /** * Process a value - handle different formats */ function processValue(value) { // Remove surrounding quotes if present if ( (value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'")) ) { value = value.slice(1, -1); } // Handle empty values if (value === '""' || value === "''") { return ''; } // Handle boolean values if (value === 'true') return true; if (value === 'false') return false; // Handle numeric values if (/^\d+$/.test(value)) return parseInt(value, 10); if (/^\d+\.\d+$/.test(value)) return parseFloat(value); return value; } /** * Extract YAML frontmatter from markdown content */ export function extractFrontmatter(content) { const frontmatterMatch = /^---\n([\s\S]*?)\n---/.exec(content); if (!frontmatterMatch) { return { frontmatter: null, content }; } const yamlContent = frontmatterMatch[1]; const frontmatter = parseYamlFrontmatter(yamlContent); const remainingContent = content.replace(frontmatterMatch[0], '').trim(); return { frontmatter, content: remainingContent }; }