#!/usr/bin/env python3 """ Deterministic Git Reconciliation Hook for MCP Memory Automatically syncs git commit events to mcp-memory to transition ADRs, resolve tech debts, complete tasks, cascade-unblock dependent tasks, and recalculate milestone statuses. """ import os import sys import json import subprocess import urllib.request import urllib.error def run_git(cmd): try: res = subprocess.run(["git"] + cmd, capture_output=True, text=True, check=True) return res.stdout.strip() except Exception: return "" def main(): port = os.environ.get("MCP_PORT", "3000") # 1. Quick check if server is running ping_url = f"http://127.0.0.1:{port}/ping" try: with urllib.request.urlopen(ping_url, timeout=1.0) as resp: if resp.status != 200: sys.exit(0) except Exception: # Server not running, silently exit sys.exit(0) # 2. Extract git metadata commit = run_git(["rev-parse", "HEAD"]) branch = run_git(["branch", "--show-current"]) author = run_git(["log", "-1", "--pretty=format:%an"]) message = run_git(["log", "-1", "--pretty=format:%B"]) # Get changed files in this commit files_raw = run_git(["diff-tree", "--no-commit-id", "--name-only", "-r", "HEAD"]) files = [f.strip() for f in files_raw.splitlines() if f.strip()] if not commit or not message: sys.exit(0) payload = { "commit": commit, "branch": branch, "author": author, "message": message, "files": files, } # 3. Post to reconciliation endpoint reconcile_url = f"http://127.0.0.1:{port}/api/git/commit" req_data = json.dumps(payload).encode("utf-8") req = urllib.request.Request( reconcile_url, data=req_data, headers={"Content-Type": "application/json"}, method="POST" ) try: with urllib.request.urlopen(req, timeout=3.0) as resp: if resp.status == 200: body = json.loads(resp.read().decode("utf-8")) res = body.get("reconciliation", {}) adrs = res.get("implemented_adrs", []) debts = res.get("resolved_tech_debts", []) tasks = res.get("completed_tasks", []) unblocked = res.get("unblocked_tasks", []) milestones = res.get("updated_milestones", []) if any([adrs, debts, tasks, unblocked, milestones]): print("\033[36m[MCP Memory Auto-Reconciled]\033[0m") if adrs: print(f" \033[32m✔ Implemented ADRs:\033[0m {', '.join(adrs)}") if debts: print(f" \033[32m✔ Resolved Tech Debts:\033[0m {', '.join(debts)}") if tasks: print(f" \033[32m✔ Completed Tasks:\033[0m {', '.join(tasks)}") if unblocked: print(f" \033[33m⚡ Unblocked Dependent Tasks:\033[0m {', '.join(unblocked)}") if milestones: print(f" \033[35m🎯 Updated Milestones:\033[0m {', '.join(milestones)}") except Exception: # Never break commit flow on failure pass if __name__ == "__main__": main()