#!/usr/bin/env python3 """ Auto-Update Context - Intelligent Context Synchronization Analyzes code changes and autonomously updates context files. Designed to be run by Claude with minimal supervision. Usage: python auto_update.py [--analyze-only] [--verbose] """ import os import sys import argparse from pathlib import Path from datetime import datetime from typing import List, Dict, Set import subprocess import re # Add lib to path for integration imports repo_root = Path(__file__).resolve().parents[6] # Go up to repo root sys.path.insert(0, str(repo_root / "lib")) try: from ccmp_integration import CCMPIntegration, is_session_active INTEGRATION_AVAILABLE = True except ImportError: INTEGRATION_AVAILABLE = False def get_recent_changes(dir_path: Path, since_days: int = 30) -> Dict: """Get summary of recent changes in directory.""" try: # Get changed files result = subprocess.run( ['git', 'diff', '--name-status', f'HEAD~{since_days*4}', 'HEAD', '--', str(dir_path)], cwd=dir_path, capture_output=True, text=True ) if result.returncode != 0: return {'files_changed': [], 'summary': {}} changes = result.stdout.strip().split('\n') added = [] modified = [] deleted = [] for change in changes: if not change: continue parts = change.split('\t', 1) if len(parts) != 2: continue status, filepath = parts if status.startswith('A'): added.append(filepath) elif status.startswith('M'): modified.append(filepath) elif status.startswith('D'): deleted.append(filepath) return { 'files_changed': added + modified + deleted, 'summary': { 'added': len(added), 'modified': len(modified), 'deleted': len(deleted) }, 'details': { 'added': added, 'modified': modified, 'deleted': deleted } } except: return {'files_changed': [], 'summary': {}} def analyze_code_patterns(dir_path: Path) -> Dict: """Analyze current code patterns in directory.""" patterns = { 'file_types': {}, 'common_imports': set(), 'naming_patterns': [], 'frameworks_detected': set() } # Analyze files for item in dir_path.iterdir(): if item.is_file() and not item.name.startswith('.'): ext = item.suffix patterns['file_types'][ext] = patterns['file_types'].get(ext, 0) + 1 # Analyze imports for common patterns if ext in ['.py', '.js', '.ts', '.jsx', '.tsx']: try: content = item.read_text() # Python imports if ext == '.py': imports = re.findall(r'^\s*(?:from|import)\s+([a-zA-Z_][a-zA-Z0-9_]*)', content, re.MULTILINE) patterns['common_imports'].update(imports[:5]) # Top 5 # Detect frameworks if 'fastapi' in content.lower(): patterns['frameworks_detected'].add('FastAPI') if 'flask' in content.lower(): patterns['frameworks_detected'].add('Flask') # JavaScript/TypeScript imports elif ext in ['.js', '.ts', '.jsx', '.tsx']: imports = re.findall(r'(?:from|require\()\s*[\'"]([^\'\"]+)', content) patterns['common_imports'].update(imports[:5]) # Detect frameworks if 'react' in content.lower(): patterns['frameworks_detected'].add('React') if 'express' in content.lower(): patterns['frameworks_detected'].add('Express') if 'vue' in content.lower(): patterns['frameworks_detected'].add('Vue') except: pass patterns['common_imports'] = list(patterns['common_imports']) patterns['frameworks_detected'] = list(patterns['frameworks_detected']) return patterns def read_existing_context(context_file: Path) -> str: """Read existing context file.""" if context_file.exists(): return context_file.read_text() return "" def needs_update(existing_context: str, current_patterns: Dict, recent_changes: Dict) -> Dict: """Determine if context needs updating and what sections.""" update_needed = { 'should_update': False, 'reasons': [], 'sections_to_update': [] } # Check if significant changes occurred total_changes = recent_changes['summary'].get('added', 0) + \ recent_changes['summary'].get('modified', 0) + \ recent_changes['summary'].get('deleted', 0) if total_changes > 5: update_needed['should_update'] = True update_needed['reasons'].append(f'{total_changes} files changed') update_needed['sections_to_update'].append('File Types') update_needed['sections_to_update'].append('Key Files') # Check if frameworks mentioned in context match detected for framework in current_patterns.get('frameworks_detected', []): if framework not in existing_context: update_needed['should_update'] = True update_needed['reasons'].append(f'New framework detected: {framework}') update_needed['sections_to_update'].append('Important Patterns') # Check if context has TODO markers if 'TODO' in existing_context or '