UNPKG

@blundergoat/goat-flow

Version:

AI coding agent harness and local dashboard for Claude Code, OpenAI Codex, Google Antigravity, and GitHub Copilot - setup audits, guardrails, structured skills, deny hooks, and persistent learning loops.

86 lines 3.56 kB
/** Parse markdown content into a map of lowercase heading names to their body text. */ function parseSections(content) { /** Accumulated heading-to-content mapping */ const sections = new Map(); /** Input split into individual lines */ const lines = content.split("\n"); let currentHeading = ""; let currentContent = []; // Iterate over lines to group content under markdown headings for (const line of lines) { /** Regex match result for lines starting with 1-3 '#' characters */ const headingMatch = line.match(/^#{1,3}\s+(.+)/); if (headingMatch) { if (currentHeading) { sections.set(currentHeading.toLowerCase(), currentContent.join("\n")); } const captured = headingMatch[1]; if (captured === undefined) continue; currentHeading = captured; currentContent = []; } else { currentContent.push(line); } } if (currentHeading) { sections.set(currentHeading.toLowerCase(), currentContent.join("\n")); } return sections; } /** * Extract the body text of a named markdown section, or null if not found. * * @param content - markdown instruction file content to search * @param sectionName - case-insensitive heading fragment that identifies the target section * @returns section body text without the heading, or null when the section is absent */ export function extractSection(content, sectionName) { /** Input split into individual lines */ const lines = content.split("\n"); let inSection = false; /** Lines collected while inside the target section */ const sectionLines = []; // Iterate over lines to find and extract the named section content for (const line of lines) { /** Regex match result for markdown heading lines */ const heading = line.match(/^#{1,3}\s+(.+)/); if (heading) { if (inSection) break; const headingText = heading[1]; if (headingText === undefined) continue; if (headingText.toLowerCase().includes(sectionName.toLowerCase())) { inSection = true; } } else if (inSection) { sectionLines.push(line); } } return sectionLines.length > 0 ? sectionLines.join("\n") : null; } // ─── Focused extraction functions ──────────────────────────────────── /** * Extract instruction file facts: existence, content, line count, and parsed sections. * * @param fs - project filesystem adapter used to read the instruction file * @param agent - agent profile that names the instruction file path * @returns instruction-file facts used by setup and harness checks */ export function extractInstructionFacts(fs, agent) { /** Raw content of the agent's instruction file (null if missing) */ const content = fs.readFile(agent.instructionFile); /** Whether the instruction file exists on disk */ const exists = content !== null; /** Number of lines in the instruction file */ const lineCount = exists ? content.split("\n").length - (content.endsWith("\n") ? 1 : 0) : 0; /** Parsed heading-to-content sections from the instruction file */ const sections = exists ? parseSections(content) : new Map(); return { exists, content, lineCount, sections }; } //# sourceMappingURL=instruction.js.map