Files
2026-08-28 11:43:34 -04:00

89 lines
3.1 KiB
Python

#!/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']}")