"""Superpower Registry for 152 Superpowers. Provides: - load_all_superpowers() - Load all 152 superpowers - get_superpower(id) - Get single superpower by ID - get_superpowers_by_band(band) - Get all superpowers in band - calculate_boost(superpower_ids) - Calculate aggregate boost - search_superpowers(query) - Search superpowers by name/description """ import json from pathlib import Path from typing import Optional, List, Dict, Any # Module-level cache _superpowers: Optional[Dict[int, dict]] = None _superpowers_list: Optional[List[dict]] = None _loaded = False _load_path: Optional[Path] = None def load_all_superpowers(path: Optional[str] = None) -> None: """Load all 152 superpowers from JSON file. Args: path: Optional path to superpowers.json file. Defaults to /home/dave/superdave/glyphs/superpowers.json """ global _superpowers, _superpowers_list, _loaded, _load_path if _loaded: return if path is None: path = "/home/dave/superdave/glyphs/superpowers.json" filepath = Path(path) if not filepath.exists(): raise FileNotFoundError(f"Superpowers file not found: {filepath}") _load_path = filepath with open(filepath) as f: data = json.load(f) # Validate count if data.get("total") != 152: raise ValueError(f"Expected 152 superpowers, got {data.get('total')}") # Build cache by ID _superpowers = {} for sp in data.get("superpowers", []): _superpowers[sp["id"]] = sp # Build sorted list _superpowers_list = sorted(_superpowers.values(), key=lambda x: x["id"]) _loaded = True def get_superpower(id: int) -> Optional[dict]: """Get a single superpower by ID. Args: id: Superpower ID (1-152) Returns: Superpower dict with id, name, boost_percent, description, band """ if not _loaded: load_all_superpowers() return _superpowers.get(id) if _superpowers else None def list_superpower_ids() -> List[int]: """List all superpower IDs (sorted). Returns: List of 152 superpower IDs [1, 2, ..., 152] """ if not _loaded: load_all_superpowers() return [sp["id"] for sp in _superpowers_list] if _superpowers_list else [] def get_superpowers_by_band(band: str) -> List[dict]: """Get all superpowers in a band. Args: band: Band identifier ("A", "B", "C", "D") Returns: List of superpower dicts in that band """ if not _loaded: load_all_superpowers() if not _superpowers_list: return [] return [sp for sp in _superpowers_list if sp.get("band") == band] def get_superpowers_by_bands(bands: List[str]) -> List[dict]: """Get all superpowers in multiple bands. Args: bands: List of band identifiers Returns: List of superpower dicts in those bands """ if not _loaded: load_all_superpowers() if not _superpowers_list: return [] return [sp for sp in _superpowers_list if sp.get("band") in bands] def calculate_boost(superpower_ids: List[int]) -> float: """Calculate aggregate boost from superpower IDs. Formula: power_boost = 1.0 + Σ(boost_percent) / 100.0 Args: superpower_ids: List of superpower IDs Returns: Aggregate boost multiplier (e.g., 2.0 = 200% effectiveness) """ if not _loaded: load_all_superpowers() total_boost = 0.0 for id in superpower_ids: sp = _superpowers.get(id) if sp: total_boost += sp.get("boost_percent", 0) / 100.0 return 1.0 + total_boost def search_superpowers(query: str, fields: Optional[List[str]] = None, limit: int = 20) -> List[dict]: """Search superpowers by query. Args: query: Search string (case-insensitive substring) fields: Fields to search (default: ["name", "description"]) limit: Maximum results Returns: List of matching superpower dicts """ if not _loaded: load_all_superpowers() if not _superpowers_list: return [] if fields is None: fields = ["name", "description"] query_lower = query.lower() results = [] for sp in _superpowers_list: for field in fields: value = sp.get(field, "") if isinstance(value, str) and query_lower in value.lower(): results.append(sp) break if len(results) >= limit: break return results def super_stats() -> dict: """Get statistics about the superpower registry. Returns: Dict with total, bands, loaded status, etc. """ if not _loaded: load_all_superpowers() if not _superpowers_list: return { "total": 0, "bands": {}, "loaded": False, } # Count by band band_counts = {} for sp in _superpowers_list: band = sp.get("band") band_counts[band] = band_counts.get(band, 0) + 1 return { "total": len(_superpowers_list), "band_counts": band_counts, "loaded": _loaded, "load_path": str(_load_path) if _load_path else None, } # Global singleton instance _adapter_instance: Optional[Any] = None def get_superpower_names(superpower_ids: List[int]) -> List[str]: """Get names for a list of superpower IDs. Args: superpower_ids: List of IDs Returns: List of superpower names """ if not _loaded: load_all_superpowers() names = [] for id in superpower_ids: sp = _superpowers.get(id) if sp: names.append(sp.get("name", f"SP{id}")) return names