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.

364 lines 13.4 kB
/** * Core shared types for goat-flow. */ /** Canonical supported AI coding agent identifiers in stable display order. */ export declare const KNOWN_AGENT_IDS: readonly ["claude", "codex", "antigravity", "copilot"]; /** Supported AI coding agent identifiers derived from the canonical tuple. */ export type AgentId = (typeof KNOWN_AGENT_IDS)[number]; /** Prompt invocation syntax an agent expects for goat-flow skills. */ type PromptInvocationStyle = "slash" | "dollar"; /** Skill mirror/source classification used by quality inventory. */ type SkillSource = "installed" | "agent-mirror" | "github-mirror"; /** * Describes an agent's file layout and enforcement mechanisms. * One profile per supported agent (Claude, Codex, Antigravity, Copilot). * * `denyMechanism` and `hookEvents` are nullable to model agents whose upstream * runtime has no project-local hook wiring for a given capability; consumers * MUST guard for the null case. */ export interface AgentProfile { id: AgentId; name: string; instructionFile: string; terminalBinary: string; setupSurfaces: string[]; promptInvocationStyle: PromptInvocationStyle; skillSource: SkillSource; supportsPostTurnHook: boolean; settingsFile: string | null; hookConfigFile: string | null; skillsDir: string; hooksDir: string | null; denyMechanism: DenyMechanism | null; denyHookFile: string | null; localPattern: string; hookEvents: HookEvents | null; } /** * Discriminated union for how an agent enforces command denials. * Agents may use settings-based deny, a deny script, or both. */ export type DenyMechanism = { type: "settings-deny"; path: string; } | { type: "deny-script"; path: string; } | { type: "both"; settingsPath: string; scriptPath: string; }; /** Hook event file names specific to each agent runtime */ interface HookEvents { preTool: string; postTurn: string | null; } /** Top-level fact container gathered by the fact extractors */ export interface ProjectFacts { root: string; stack: StackInfo; agents: AgentFacts[]; shared: SharedFacts; } /** Detected build toolchain for the target project */ export interface StackInfo { languages: string[]; buildCommand: string | null; testCommand: string | null; lintCommand: string | null; formatCommand: string | null; /** Approximate count of source files (excludes node_modules, vendor, dist, .git) */ sourceFileCount: number; /** Extended project signals detected during setup-time analysis */ signals: ProjectSignals; } /** Extended detection signals for richer setup prompts. */ export interface ProjectSignals { /** Code generation tools found (sqlc, Hygen, protobuf, openapi-generator) */ codeGenTools: string[]; /** Deployment/infrastructure platforms found (amplify, terraform, docker, fly, vercel) */ deployPlatforms: string[]; /** LLM integration signals (model provider env vars, SDK imports) */ llmIntegration: boolean; /** Static analysis tools with detected strictness level */ staticAnalysis: Array<{ tool: string; level: string | null; }>; /** PHI/compliance keywords detected in docs or instructions */ complianceSignals: boolean; /** Formatter coverage: languages with detected formatters vs languages without */ formatterGaps: string[]; } /** Per-bucket learning-loop freshness + health record used by `goat-flow stats`. */ export interface BucketFreshness { /** Relative path of the bucket file */ path: string; /** `last_reviewed` date from frontmatter in YYYY-MM-DD form, or null if missing/invalid */ lastReviewed: string | null; /** Whole days between last_reviewed and "now"; null when lastReviewed is unknown */ freshnessDays: number | null; /** Freshness band: <=30d fresh, 31-90d aging, >90d stale, unknown if no valid date */ freshnessBand: "fresh" | "aging" | "stale" | "unknown"; /** Entries counted live in this bucket (## Footgun/Lesson/Pattern headings) */ entryCount: number; /** Stale file refs found in this bucket */ staleRefs: string[]; /** Invalid line refs (line out of bounds or missing semantic anchor) found in this bucket */ invalidLineRefs: string[]; /** Most recent `**Created:**` or `**Updated:**` date in the body, YYYY-MM-DD or null. * Used to detect frontmatter `last_reviewed` that is stale relative to entry dates. */ maxEntryDate: string | null; /** File content size in bytes. Used by `goat-flow stats --check` for bucket-size warnings. */ sizeBytes: number; /** Total line count of the bucket file. */ lineCount: number; } /** Learning-loop artifact kinds in the order the retrieval and stats pipelines understand. */ export type LearningLoopEntryKind = "footgun" | "lesson" | "pattern" | "decision"; /** Compact parsed learning-loop entry used by bounded prompt retrieval. */ export interface LearningLoopEntryFact { sourcePath: string; kind: LearningLoopEntryKind; title: string; status: "active" | "resolved" | null; created: string | null; updated: string | null; resolved: string | null; excerpt: string; staleRefs: string[]; invalidLineRefs: string[]; hasValidAnchor: boolean; bucketSizeBytes: number; order: number; } /** Stable project-wide fact schema shared by audits, stats, setup prompts, and dashboard APIs. */ export interface SharedFacts { footguns: { exists: boolean; hasEvidence: boolean; entryCount: number; labelCount: number; hasEvidenceLabels: boolean; dirMentions: Map<string, number>; staleRefs: string[]; invalidLineRefs: string[]; duplicateSurfacePaths: string[]; totalRefs: number; validRefs: number; formatDiagnostic: string | null; path: string; /** Per-bucket freshness records; empty when the directory is missing. */ buckets: BucketFreshness[]; }; lessons: { exists: boolean; hasEntries: boolean; entryCount: number; staleRefs: string[]; invalidLineRefs: string[]; duplicateSurfacePaths: string[]; formatDiagnostic: string | null; path: string; /** Per-bucket freshness records; empty when the directory is missing. */ buckets: BucketFreshness[]; }; decisions: { dirExists: boolean; fileCount: number; path: string; hasRealContent: boolean; }; config: { exists: boolean; valid: boolean; warningCount: number; errorCount: number; parseError: string | null; lineLimits: { target: number; limit: number; }; userRole: "developer" | "investigator" | "tester"; }; architecture: { exists: boolean; lineCount: number; }; ignoreFiles: { copilotignore: boolean; cursorignore: boolean; }; gitignore: { exists: boolean; hasRequiredEntries: boolean; }; preflightScript: { exists: boolean; }; skillConventions: { exists: boolean; }; localInstructions: { dirExists: boolean; location: "ai" | "github" | null; aiDirExists: boolean; githubDirExists: boolean; duplicateSurfacePaths: string[]; fileCount: number; hasRouter: boolean; hasValidRouter: boolean; routerNeedsFix: string | null; hasConventions: boolean; conventionsHasContent: boolean; hasFrontend: boolean; hasBackend: boolean; hasCodeReview: boolean; hasGitCommit: boolean; conventionsContent: string | null; localFileSizes: Array<{ path: string; lines: number; }>; path: string; }; gitCommitInstructions: { exists: boolean; path: string | null; requiredPath: string; misplacedPaths: string[]; }; /** Total line count across canonical local-instruction files. */ localInstructionsLineCount: number; /** Parsed entries for deterministic, bounded prompt retrieval. */ learningLoopEntries: LearningLoopEntryFact[]; } /** Per-agent facts gathered from instruction files, settings, skills, and hooks */ export interface AgentFacts { agent: AgentProfile; instruction: { exists: boolean; content: string | null; lineCount: number; sections: Map<string, string>; }; settings: { exists: boolean; valid: boolean; parsed: unknown; hasDenyPatterns: boolean; }; skills: { /** All skill directories present under the agent's skills dir that contain a SKILL.md file */ installedDirs: string[]; found: string[]; missing: string[]; allPresent: boolean; /** Map from skill name to its embedded goat-flow-skill-version (null if missing) */ versions: Record<string, string | null>; /** Number of skills with a version older than the current SKILL_VERSION */ outdatedCount: number; /** Whether the goat dispatcher skill is installed */ hasDispatcher: boolean; quality: { withStep0: number; withHumanGate: number; withConstraints: number; withPhases: number; withConversational: number; withChoices: number; withOutputFormat: number; withSharedConventions: number; /** Number of malformed (unclosed) markdown fence blocks across all skill files */ malformedFenceCount: number; /** Skills where Step 0 Jaccard similarity to template > 0.9 (unadapted) */ unadaptedCount: number; /** Total remaining <!-- ADAPT: --> comments across all skill files */ adaptCommentCount: number; total: number; }; }; hooks: { denyExists: boolean; denyHasBlocks: boolean; /** True when deny is via settings.json patterns (not a shell script). jq/chaining checks are N/A for config-based deny. */ denyIsConfigBased: boolean; denyUsesJq: boolean; denyHandlesChaining: boolean; denyBlocksRmRf: boolean; denyBlocksGitPush: boolean; denyBlocksChmod: boolean; denyBlocksPipeToShell: boolean; denyBlocksCloudDestructive: boolean; /** True when the deny hook is registered as a pre-tool-use hook in agent settings */ denyIsRegistered: boolean; denyRegisteredPath: string | null; postTurnExists: boolean; postTurnRegistered: boolean; postTurnRegisteredPath: string | null; postTurnExecutable: boolean; postTurnExitsZero: boolean; postTurnHasValidation: boolean; postTurnSwallowsFailures: boolean; /** Hook scripts containing hardcoded absolute paths (not wrapped in $(git rev-parse)) */ absolutePathHooks: string[]; readDenyCoversSecrets: boolean; /** True when the Bash deny hook blocks direct literal secret-bearing paths * (.env, /.ssh/, /.aws/, .pem/.key/.pfx). Settings/Codex permission * file-read denies do not cover Bash commands, so this is direct-path * defence in depth. */ bashDenyCoversSecrets: boolean; }; deny: { gitCommitBlocked: boolean; gitPushBlocked: boolean; }; router: { exists: boolean; paths: string[]; resolved: number; unresolved: string[]; }; localContext: { files: string[]; warranted: string[]; missing: string[]; }; } /** * Stable read-only filesystem schema for the scan engine. * Allows swapping real FS for in-memory FS during testing while preserving non-throwing read semantics. */ export interface ReadonlyFS { /** Return path existence; implementations should report inaccessible paths as false. */ exists(path: string): boolean; /** Read UTF-8 text or return null when the file is missing or unreadable. */ readFile(path: string): string | null; /** Count text lines, returning 0 when the file cannot be read. */ lineCount(path: string): number; /** Parse JSON defensively, returning null for missing, unreadable, or malformed files. */ readJson(path: string): unknown; /** List child names; missing and unreadable directories intentionally return an empty list. */ listDir(path: string): string[]; /** Report whether a file can be executed by the current platform. */ isExecutable(path: string): boolean; /** Expand goat-flow's small relative glob syntax into matching POSIX-shaped paths. */ glob(pattern: string): string[]; /** Check whether a glob has any match without requiring callers to materialize every path. */ existsGlob(pattern: string): boolean; } /** Parsed command-line arguments for the goat-flow CLI */ export interface CLIOptions { projectPath: string; format: "json" | "text" | "markdown" | "sarif"; agent: AgentId | null; isVerbose: boolean; output: string | null; isDevMode: boolean; showHelp: boolean; showVersion: boolean; } export {}; //# sourceMappingURL=types.d.ts.map