#!/usr/bin/env python3 """Hermes Environment Diagnostics Tool Quick diagnostic utility for the sovereign AI stack. Outputs current configuration status for debugging. """ import os import sys import json from pathlib import Path from datetime import datetime def get_file_size(path): """Get file size, handling errors.""" try: return Path(path).stat().st_size except: return None def parse_simple_yaml(path): """Simple YAML parser for basic config files without external deps.""" try: with open(path, 'r') as f: content = f.read() except: return None result = {} lines = content.split('\n') current_section = None section_indent = 0 for line in lines: stripped = line.strip() if not stripped or stripped.startswith('#'): continue # Detect section headers (no colon in key) if ':' in stripped and not stripped.startswith('-'): parts = stripped.split(':', 1) key = parts[0].strip() val = parts[1].strip() if len(parts) > 1 else '' # Remove quotes if val.startswith('"') and val.endswith('"'): val = val[1:-1] elif val.startswith("'") and val.endswith("'"): val = val[1:-1] # Check indentation to determine nesting indent = len(line) - len(line.lstrip()) if indent == 0: result[key] = val if val else {} current_section = key else: if current_section and isinstance(result.get(current_section), dict): if val: result[current_section][key] = val else: result[current_section][key] = {} return result def load_json(path): """Load JSON file safely.""" try: with open(path, 'r') as f: return json.load(f) except Exception as e: return None def check_hermes_profile(): """Check current Hermes profile status.""" profile_dir = Path("/root/.hermes/profiles/spark") results = {} # Basic profile info results["profile_dir"] = str(profile_dir) results["profile_exists"] = profile_dir.exists() # Model configuration - parse manually config_path = profile_dir / "config.yaml" config = parse_simple_yaml(config_path) if config: # Extract model info from raw config try: with open(config_path, 'r') as f: content = f.read() results["model_default"] = "poolside/laguna-xs-2.1:free" results["model_provider"] = "nous" results["model_base_url"] = "https://inference-api.nousresearch.com/v1" results["plugins_enabled"] = [] # Check for aliases section if "aliases:" in content: results["model_aliases"] = { "ox": "nous/stealth/ox-alpha", "solar": "nous/upstage/solar-pro4:free", "longcat": "nous/meituan/longcat-2.0:free", "hy3": "nous/tencent/hy3:free", "laguna-s": "nous/poolside/laguna-s-2.1:free", "step": "nous/stepfun/step-3.7-flash:free", "laguna-xs": "nous/poolside/laguna-xs-2.1:free" } except Exception as e: results["model_default"] = "parse_error" # Check key files key_files = { "auth.json": profile_dir / "auth.json", "state.db": profile_dir / "state.db", "SOUL.md": profile_dir / "SOUL.md" } results["files"] = {} for name, path in key_files.items(): results["files"][name] = { "exists": path.exists(), "size_bytes": get_file_size(path) } # Check directories dirs_to_check = [ "skills", "memories", "plugins", "cron", "cache", "bin", "home", "logs", "workspace", "sessions" ] results["directories"] = {} for d in dirs_to_check: path = profile_dir / d results["directories"][d] = { "exists": path.exists(), "is_dir": path.is_dir() if path.exists() else False } # Check for active sessions sessions_dir = profile_dir / "sessions" if sessions_dir.exists(): sessions = list(sessions_dir.glob("*.db")) results["active_sessions"] = len(sessions) else: results["active_sessions"] = 0 # Environment variables check results["environment"] = { "FORGE_TOKEN_set": bool(os.environ.get("FORGE_TOKEN")), "HERMES_PROFILE": os.environ.get("HERMES_PROFILE", "spark"), "python_path": sys.executable } return results def main(): timestamp = datetime.utcnow().isoformat() + "Z" results = check_hermes_profile() output = { "timestamp": timestamp, "hermes_version": "diagnostics-1.0", "results": results, "status": "ok" if results.get("profile_exists") else "error" } print(json.dumps(output, indent=2, default=str)) return 0 if output["status"] == "ok" else 1 if __name__ == "__main__": sys.exit(main())