context.py
1 from __future__ import annotations 2 3 from dataclasses import dataclass 4 from pathlib import Path 5 6 7 @dataclass(frozen=True) 8 class PortContext: 9 source_root: Path 10 tests_root: Path 11 assets_root: Path 12 archive_root: Path 13 python_file_count: int 14 test_file_count: int 15 asset_file_count: int 16 archive_available: bool 17 18 19 def build_port_context(base: Path | None = None) -> PortContext: 20 root = base or Path(__file__).resolve().parent.parent 21 source_root = root / 'src' 22 tests_root = root / 'tests' 23 assets_root = root / 'assets' 24 archive_root = root / 'archive' / 'claw_code_ts_snapshot' / 'src' 25 return PortContext( 26 source_root=source_root, 27 tests_root=tests_root, 28 assets_root=assets_root, 29 archive_root=archive_root, 30 python_file_count=sum(1 for path in source_root.rglob('*.py') if path.is_file()), 31 test_file_count=sum(1 for path in tests_root.rglob('*.py') if path.is_file()), 32 asset_file_count=sum(1 for path in assets_root.rglob('*') if path.is_file()), 33 archive_available=archive_root.exists(), 34 ) 35 36 37 def render_context(context: PortContext) -> str: 38 return '\n'.join([ 39 f'Source root: {context.source_root}', 40 f'Test root: {context.tests_root}', 41 f'Assets root: {context.assets_root}', 42 f'Archive root: {context.archive_root}', 43 f'Python files: {context.python_file_count}', 44 f'Test files: {context.test_file_count}', 45 f'Assets: {context.asset_file_count}', 46 f'Archive available: {context.archive_available}', 47 ])