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.

111 lines 4.42 kB
import { pass, fail } from "./helpers.js"; import { collectMarkdownFiles } from "./helpers.js"; const VERIFIED_ON = "2026-04-18"; /** Return the recovery provenance. */ function recoveryProvenance(type, paths, sourceType = "spec") { return { source_type: sourceType, source_urls: [], verified_on: VERIFIED_ON, normative_level: type === "integrity" ? "MUST" : type === "advisory" ? "SHOULD" : "BEST_PRACTICE", evidence_paths: paths, }; } /** * Count markdown checkbox markers without interpreting task completion. * * Recovery checks only report whether milestone notes contain local workflow * state; they intentionally avoid scoring incomplete checkboxes as failures. */ function countTaskMarkers(content) { return content.match(/- \[[ xX]\]/g)?.length ?? 0; } const milestoneTracking = { id: "milestone-tracking", name: "Milestone tracking configured", concern: "recovery", type: "integrity", provenance: recoveryProvenance("integrity", [ "docs/harness-audit.md", ".goat-flow/architecture.md", ".goat-flow/plans/README.md", ]), /** Run the Milestone tracking configured check. */ run: (ctx) => { const plansDir = ".goat-flow/plans"; const buildDetails = (fileCount) => ({ recovery: ctx.agents.map((af) => ({ agent: af.agent.id, dir: plansDir, fileCount, })), }); if (!ctx.fs.exists(plansDir)) { return fail(["No plans directory found"], ["Create .goat-flow/plans/ for milestone tracking"], [ "Create .goat-flow/plans/ so optional task, roadmap, and milestone notes have a stable home.", ], buildDetails(0)); } const allMdFiles = collectMarkdownFiles(ctx.fs, plansDir); if (allMdFiles.length === 0) { return pass([ "Plans directory exists (empty - valid for new projects; plan tracking is optional)", ], buildDetails(0)); } const markerCounts = []; for (const markdownFile of allMdFiles) { const content = ctx.fs.readFile(markdownFile); if (content) markerCounts.push(countTaskMarkers(content)); } const totalMarkers = markerCounts.reduce((sum, count) => sum + count, 0); const findings = [ `Plans directory exists with ${allMdFiles.length} markdown file(s) and ${totalMarkers} checkbox marker(s)`, "Task and milestone content is optional local workflow state; checkbox completion, status, testing gates, and roadmap progress are not audited.", ]; return pass(findings, buildDetails(allMdFiles.length)); }, }; const sessionLogs = { id: "session-logs", name: "Session logs directory", concern: "recovery", type: "integrity", provenance: recoveryProvenance("integrity", [ "docs/harness-audit.md", ".goat-flow/architecture.md", ]), /** Run the Session logs directory check. */ run: (ctx) => { const logsDir = ".goat-flow/logs/sessions"; const buildDetails = (fileCount) => ({ recovery: ctx.agents.map((af) => ({ agent: af.agent.id, dir: logsDir, fileCount, })), }); if (!ctx.fs.exists(logsDir)) { return fail(["No session logs directory"], ["Create .goat-flow/logs/sessions/ directory"], [ "Create .goat-flow/logs/sessions/ and start logging sessions for continuity between conversations.", ], buildDetails(0)); } let fileCount = 0; try { fileCount = ctx.fs .listDir(logsDir) .filter((fileName) => fileName.endsWith(".md")).length; } catch { return fail(["Session logs path exists but is not readable as a directory"], ["Ensure .goat-flow/logs/sessions/ is a directory, not a file"], [ "Remove or rename the file at .goat-flow/logs/sessions and recreate as a directory.", ], buildDetails(0)); } return pass(["Session logs directory exists"], buildDetails(fileCount)); }, }; export const RECOVERY_CHECKS = [milestoneTracking, sessionLogs]; //# sourceMappingURL=check-recovery.js.map