#!/usr/bin/env python3 """Scan ~/.hermes/skills/ for corrupted .py scripts. Usage: python corruption-scanner.py [--fix-dir /path/to/output] Output: JSON summary of clean vs corrupted files. """ import json, os, sys from pathlib import Path def scan_skills(base_dir): results = {"clean": [], "corrupted": [], "skipped": []} for root, dirs, files in os.walk(base_dir): if '__pycache__' in root or 'venv' in root: continue for fname in files: if not fname.endswith('.py'): continue fpath = os.path.join(root, fname) size = os.path.getsize(fpath) # Skip empty __init__.py (normal) if fname == '__init__.py' and size <= 50: results["skipped"].append({"path": fpath, "reason": "empty __init__.py"}) continue try: with open(fpath, 'r') as f: content = f.read(1000) first_line = content.strip().split('\n')[0].lower() if '% partial rewrite' in first_line[:200] or 'latex' in first_line[:200]: results["corrupted"].append({ "path": fpath, "size": size, "type": "latex_contamination" }) elif first_line.startswith('%pdf') or '%PDF' in first_line[:20]: results["corrupted"].append({ "path": fpath, "size": size, "type": "pdf_binary" }) elif len(content) > 200000: results["corrupted"].append({ "path": fpath, "size": size, "type": "oversized" }) else: results["clean"].append({"path": fpath, "size": size}) except UnicodeDecodeError: results["skipped"].append({"path": fpath, "reason": "binary file"}) except Exception as e: results["skipped"].append({"path": fpath, "reason": str(e)}) return results if __name__ == '__main__': base = os.environ.get('HERMES_HOME', str(Path.home() / '.hermes')) skills_dir = os.path.join(base, 'skills') fix_dir = None args = sys.argv[1:] if '--fix-dir' in args: idx = args.index('--fix-dir') if idx + 1 < len(args): fix_dir = args[idx + 1] results = scan_skills(skills_dir) print(json.dumps(results, indent=2, ensure_ascii=False)) # Summary print(f"\n{'='*60}") print(f"Scan complete:") print(f" Clean: {len(results['clean'])}") print(f" Corrupted: {len(results['corrupted'])}") print(f" Skipped: {len(results['skipped'])}") if results['corrupted']: print(f"\nCorrupted files:") for f in results['corrupted']: print(f" ❌ {f['path']} ({f['size']:,} bytes) - {f['type']}")