"""Git history tools — log, diff, blame — over the campus repo.""" from dataclasses import dataclass from tools.guard import run_checked @dataclass class GitTools: repo_root: str def log(self, since: str = "7 days ago", limit: int = 20, path: str = "") -> str: argv = ["git", "log", "--oneline", f"--since={since}", f"-{limit}"] if path: argv += ["--", path] result = run_checked(argv, cwd=self.repo_root, timeout=15) return result.stdout if result.ok else f"(git log failed: {result.stderr or result.blocked_reason})" def diff(self, ref: str = "HEAD~5..HEAD", path: str = "", stat_only: bool = False) -> str: argv = ["git", "diff", ref] if stat_only: argv.append("--stat") if path: argv += ["--", path] result = run_checked(argv, cwd=self.repo_root, timeout=30) out = result.stdout if result.ok else f"(git diff failed: {result.stderr or result.blocked_reason})" return out[:20_000] def blame(self, path: str, line_start: int = 1, line_end: int = 50) -> str: argv = ["git", "blame", "-L", f"{line_start},{line_end}", "--date=short", "--", path] result = run_checked(argv, cwd=self.repo_root, timeout=20) return result.stdout if result.ok else f"(git blame failed: {result.stderr or result.blocked_reason})" def recent_authors(self, path: str, limit: int = 5) -> str: argv = ["git", "log", f"-{limit}", "--format=%h %ad %an %s", "--date=short", "--", path] result = run_checked(argv, cwd=self.repo_root, timeout=15) return result.stdout if result.ok else ""