"""Automated codebase modularization and frontend payload inventory.""" from __future__ import annotations import hashlib import json import os from datetime import datetime, timedelta, timezone from pathlib import Path from typing import Iterable ROOT = Path(__file__).resolve().parents[1] TAIPEI_TZ = timezone(timedelta(hours=8)) PYTHON_DEBT_LINES = 800 FRONTEND_P0_BYTES = 50_000 FRONTEND_P1_BYTES = 20_000 IN_PROGRESS_PYTHON_PATHS = { "app.py", "routes/openclaw_bot_routes.py", "run_scheduler.py", "services/pchome_mapping_backlog_service.py", } IGNORED_PARTS = { ".claude", ".docker", ".git", ".gitea", ".github", ".pytest_cache", ".venv", "__pycache__", "aiops-core", "backups", "data", "docs", "k8s", "logs", "memory", "n8n-workflows", "node_modules", "runtime_artifacts", "secrets", "ssl", "tests", "venv", } def _iter_python_files(root: Path) -> Iterable[Path]: for path in root.rglob("*.py"): relative = path.relative_to(root) if any(part in IGNORED_PARTS for part in relative.parts): continue yield path def _iter_frontend_files(root: Path) -> Iterable[Path]: for folder in ("templates", "static", "web/templates", "web/static"): base = root / folder if not base.exists(): continue for path in base.rglob("*"): if path.is_file() and path.suffix.lower() in {".html", ".css", ".js"}: yield path def _line_count(path: Path) -> int: with path.open(encoding="utf-8", errors="ignore") as handle: return sum(1 for _ in handle) def _priority_for_python(lines: int) -> str: if lines >= 2_000: return "P0" if lines >= PYTHON_DEBT_LINES: return "P1" return "P2" def _priority_for_frontend(size_bytes: int) -> str: return "P0" if size_bytes >= FRONTEND_P0_BYTES else "P1" def _split_direction(path: str) -> str: if path.startswith("routes/"): return "separate route glue, queries, commands, and projections" if path == "scheduler.py" or path == "run_scheduler.py": return "separate task registry, domain jobs, runtime workers, and receipts" if path.startswith("services/"): return "separate policy, adapters, execution, verification, and reporting" if path == "app.py": return "extract app factory, extensions, blueprint registry, and startup guards" return "separate cohesive domain responsibilities behind stable interfaces" def _work_item_id(kind: str, path: str) -> str: digest = hashlib.sha256(path.encode("utf-8")).hexdigest()[:10] return f"{kind}-{digest}" def _runtime_controls(root: Path) -> list[dict]: app_source = (root / "app.py").read_text(encoding="utf-8") bot_source = (root / "routes/openclaw_bot_routes.py").read_text(encoding="utf-8") learning_source = (root / "services/openclaw_learning_service.py").read_text(encoding="utf-8") login_source = (root / "templates/login.html").read_text(encoding="utf-8") registration = bot_source[bot_source.index("@openclaw_bot_bp.record_once") :] return [ { "id": "web_no_eager_scheduler_import", "passed": "from scheduler import" not in app_source, }, { "id": "openclaw_web_registration_no_scheduler_boot", "passed": "start_scheduler()" not in registration, }, { "id": "embedding_worker_explicit_runtime_owner", "passed": "Thread(target=_embedding_worker_loop" not in learning_source, }, { "id": "text_compression_enabled", "passed": "Compress(app)" in app_source and "COMPRESS_ALGORITHM" in app_source, }, { "id": "versioned_static_immutable", "passed": "max-age=31536000, immutable" in app_source, }, { "id": "login_has_no_third_party_assets", "passed": "https://" not in login_source and "