/** * @slowcook 0.19.0-alpha.43 — git-history attention layer for the refine * history-index. * * Motivated by the "Attention Is All You Need" thread (memory: * project_bounded_attention_validation_2026_04_25): a brownfield repo IS * the product of a sequential process (git commits). Versioning history * — diffs, commit messages, PR descriptions, specs — is a strong signal * for which existing components/props/tests/routes/migrations are most * relevant to a new story, BUT raw commit history is noisy. We extract * four narrower signals: * * 1. Rename chains — `git log --follow` so look-ups don't miss * historical names (e.g. ReactionsPage → * MemberReactionsPage). * 2. Change-coupling — file pairs that co-change in the same * commits; surfaces architectural couplings * file-system layout misses. * 3. Recent PRs per file — PR descriptions are higher-quality "Keys" * than raw commit messages because they're * intent-shaped, not change-shaped. * 4. PR+spec corpus — flat searchable index of PR descriptions * and spec yaml summaries so downstream agents * can keyword-retrieve prior intent before * writing new code. * * Deliberately deterministic (no embeddings). Embedding upgrade is a * future Phase 3 step; this lower-cost version ships the contract first. * * All four are graceful-degradation: missing git history, missing gh, * unauthenticated gh, no PRs, no specs — each path returns an empty * structure plus a warning string. The orchestrator NEVER throws. */ export interface CoChangeEntry { /** repo-relative path of the co-changing file */ file: string; /** fraction of this file's co-change events that landed on `file` (0..1, 2dp) */ strength: number; } export interface PRRecord { number: number; title: string; body: string; merged_at: string | null; files: string[]; } export interface PRSpecCorpusEntry { source: "pr" | "spec"; /** Stable id: "pr#123" or "spec:story-007". */ id: string; title: string; /** First ~500 chars of the body / spec summary. */ excerpt: string; /** Files touched (empty for specs). */ files_touched: string[]; /** ISO date or "" if not applicable. */ date: string; /** Lower-cased, stopword-stripped tokens for cheap keyword retrieval. */ tokens: string[]; } export interface GitAttentionData { enriched_at: string; /** current_file -> historical paths it was renamed from, newest-first. */ rename_chains: Record; /** file -> top-K co-changing files (by frequency in same commits). */ co_changes: Record; /** file -> last 5 PRs that touched it (newest-first; merged before open). */ recent_prs_by_file: Record; /** Flat searchable corpus of PR descriptions + spec yaml summaries. */ pr_spec_corpus: PRSpecCorpusEntry[]; /** Non-fatal degradation notices ("gh not installed", "git history shallow", etc.). */ warnings: string[]; } export interface GitAttentionOptions { repoRoot: string; /** Files we want enrichment for (typically the union of components/api/tests/migrations from the history index). */ trackedFiles: string[]; /** Months of git log to consider for co-change. Default 6. */ coChangeWindowMonths?: number; /** Skip commits with more files than this (mass refactor filter). Default 50. */ coChangeMaxFilesPerCommit?: number; /** How many co-changes to keep per file. Default 5. */ coChangesPerFile?: number; /** How many recent PRs to fetch from gh. Default 50. */ prsToFetch?: number; /** Injectable for tests: override `git -C ...` */ gitExec?: (cmd: string) => string; /** Injectable for tests: override `gh ...` */ ghExec?: (cmd: string) => string; } export declare function computeGitAttention(opts: GitAttentionOptions): GitAttentionData; export declare function computeRenameChains(files: string[], git: (cmd: string) => string): Record; /** * Parse `git log --follow --name-status -M` output for a single file. * Each rename is a line `R\told\tnew`. Returns OLD paths in the * order git reports them (newest commit first, so most-recent rename * is index 0). */ export declare function parseRenameChain(stdout: string, currentFile: string): string[]; export interface CoChangeBuildOptions { windowMonths: number; maxFilesPerCommit: number; topPerFile: number; } export declare function computeCoChanges(trackedFiles: string[], git: (cmd: string) => string, opts: CoChangeBuildOptions): Record; export declare function parseLogIntoCommits(stdout: string): Array<{ sha: string; files: string[]; }>; export declare function fetchRecentPRs(gh: (cmd: string) => string, limit: number): PRRecord[]; export declare function parseGhPRList(stdout: string): PRRecord[]; export declare function indexPRsByFile(prs: PRRecord[], files: string[]): Record; /** * Lowercase, stopword-stripped, deduped token list capped at 60. Cheap * substitute for embeddings — agents can intersect query tokens with * each corpus entry's `tokens` to rank relevance without an LLM call. * * Embedding upgrade is Phase 3 (slowcook 0.14.0+, evidence-gated). Until * then this is what we ship. */ export declare function tokeniseForCorpus(text: string): string[]; export declare function buildPRSpecCorpus(prs: PRRecord[], repoRoot: string): PRSpecCorpusEntry[]; //# sourceMappingURL=git-attention.d.ts.map