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.

109 lines 5.12 kB
import { extractFootgunFacts, extractLessonsFacts, extractLearningLoopEntries, } from "./learning-loop.js"; import { isDecisionRecordMarkdown } from "./decision-files.js"; import { extractGitignoreFacts } from "./ci.js"; import { extractLocalInstructions } from "./local-instructions.js"; /** Extract existence and line-count facts for the architecture doc. */ function extractArchitectureFacts(fs) { const exists = fs.exists(".goat-flow/architecture.md"); return { exists, lineCount: exists ? fs.lineCount(".goat-flow/architecture.md") : 0, }; } /** Count total markdown lines across canonical local-instruction files. */ function countLocalInstructionLines(localInstructions) { return localInstructions.localFileSizes.reduce((total, file) => total + file.lines, 0); } /** Extract decisions directory facts: existence and file count. */ function extractDecisionsFacts(fs, rawPath) { const path = rawPath.replace(/\/$/, ""); /** Whether the decisions directory exists */ const dirExists = fs.exists(path); /** Count of ADR markdown files in decisions directory, excluding metadata files. */ const files = dirExists ? fs.listDir(path).filter(isDecisionRecordMarkdown) : []; const fileCount = files.length; // Require at least one ADR with substantive Context and Decision sections. let hasRealContent = false; for (const fileName of files) { const content = fs.readFile(`${path}/${fileName}`); if (!content) continue; const hasContext = /^## (?:Context|Background|Problem)\s*\n([\s\S]{50,}?)(?=^## |$)/m.test(content); const hasDecision = /^## (?:Decision|Rationale|Resolution)\s*\n([\s\S]{50,}?)(?=^## |$)/m.test(content); const startsWithTodo = /^## (?:Context|Background|Problem|Decision|Rationale|Resolution)\s*\n\s*(?:TODO|TBD)/im.test(content); if (hasContext && hasDecision && !startsWithTodo) { hasRealContent = true; break; } } return { dirExists, fileCount, path, hasRealContent }; } /** * Resolve the project-local commit guidance location. * * Canonical home is docs/coding-standards/git-commit.md: one file serves both humans and agents. * IDEs auto-read .github/copilot-instructions.md (which points here), not a bespoke .github commit * file, so the legacy .github locations are reported as misplaced and flagged for a move. The check * is repo-wide and intentionally does not depend on a .github/ directory existing. * * @param fs - Read-only filesystem used to probe the canonical and legacy commit-doc locations. * @returns Commit-guidance facts: existence, resolved path, the required canonical path, and any misplaced legacy copies. */ function extractGitCommitInstructionFacts(fs) { const canonicalPath = "docs/coding-standards/git-commit.md"; const legacyPaths = [ ".github/git-commit-instructions.md", ".github/instructions/git-commit.md", ]; const canonicalExists = fs.exists(canonicalPath); return { exists: canonicalExists, path: canonicalExists ? canonicalPath : null, requiredPath: canonicalPath, misplacedPaths: canonicalExists ? [] : legacyPaths.filter((path) => fs.exists(path)), }; } /** * Extract project-wide shared facts from docs, CI, and config files. * * @param fs - project filesystem adapter used by shared fact extractors * @param configState - parsed goat-flow config state to expose beside filesystem facts * @returns shared project facts consumed by setup, audit, and dashboard surfaces */ export function extractSharedFacts(fs, configState) { const localInstructions = extractLocalInstructions(fs); return { footguns: extractFootgunFacts(fs, configState), lessons: extractLessonsFacts(fs, configState), config: { exists: configState.exists, valid: configState.valid, warningCount: configState.warnings.length, errorCount: configState.errors.length, parseError: configState.parseError, lineLimits: configState.config.lineLimits, userRole: configState.config.userRole, }, architecture: extractArchitectureFacts(fs), ignoreFiles: { copilotignore: fs.exists(".copilotignore"), cursorignore: fs.exists(".cursorignore"), }, gitignore: extractGitignoreFacts(fs), preflightScript: { exists: fs.exists("scripts/preflight-checks.sh") }, skillConventions: { exists: fs.exists(".goat-flow/skill-docs/skill-preamble.md"), }, // changelog removed - project-level concern, not AI workflow. decisions: extractDecisionsFacts(fs, configState.config.decisions.path), localInstructions, gitCommitInstructions: extractGitCommitInstructionFacts(fs), localInstructionsLineCount: countLocalInstructionLines(localInstructions), learningLoopEntries: extractLearningLoopEntries(fs, configState), }; } //# sourceMappingURL=index.js.map