Download sidebyside/scripts/extract_hermes.py from smlflg/HarnessEcosystem: direct link, hf CLI and curl.
- Browser
- Download file 40.4 kB
-
https://huggingface.co/smlflg/HarnessEcosystem/resolve/main/sidebyside/scripts/extract_hermes.py
- Command line
-
hf download hf://smlflg/HarnessEcosystem/sidebyside/scripts/extract_hermes.py
-
curl -L -o extract_hermes.py https://huggingface.co/smlflg/HarnessEcosystem/resolve/main/sidebyside/scripts/extract_hermes.py
40.4 kB
| """Safe Hermes data extraction. | |
| This module exposes `extract_hermes(home: Path) -> dict` and performs no work | |
| at import time. It reads a constrained set of files under `~/.hermes` and | |
| `~/.local/state/hermes`, summarizes what it finds, and avoids embedding raw | |
| secrets or large prompt/request payloads. | |
| """ | |
| from __future__ import annotations | |
| import json | |
| import os | |
| import re | |
| import sqlite3 | |
| from pathlib import Path | |
| from typing import Any, Iterable | |
| MAX_SAMPLE_ITEMS = 8 | |
| MAX_TEXT_PREVIEW = 180 | |
| LOW_USAGE_SKILL_THRESHOLD = 3 | |
| SKIP_DIR_NAMES = { | |
| ".git", | |
| ".mypy_cache", | |
| ".pytest_cache", | |
| ".ruff_cache", | |
| ".uv-cache", | |
| ".venv", | |
| "__pycache__", | |
| "build", | |
| "dist", | |
| "node_modules", | |
| "site-packages", | |
| "venv", | |
| } | |
| def extract_hermes(home: Path) -> dict: | |
| home = Path(home).expanduser() | |
| hermes_dir = home / ".hermes" | |
| state_dir = home / ".local" / "state" / "hermes" | |
| sources: list[dict[str, Any]] = [] | |
| warnings: list[str] = [] | |
| discoveries: list[dict[str, Any]] = [] | |
| config = _extract_config(hermes_dir, state_dir, sources, warnings) | |
| status = _extract_status(hermes_dir, state_dir, config, sources, warnings) | |
| extensions = _extract_extensions(hermes_dir, state_dir, sources, warnings) | |
| usage = _extract_usage(hermes_dir, state_dir, sources, warnings) | |
| instruction_layers = _extract_instruction_layers(hermes_dir, state_dir, sources, warnings) | |
| _add_discoveries(discoveries, status, config, extensions, usage) | |
| return { | |
| "id": "hermes", | |
| "name": "Hermes", | |
| "status": status, | |
| "config": config, | |
| "instruction_layers": instruction_layers, | |
| "extensions": extensions, | |
| "usage": usage, | |
| "discoveries": discoveries, | |
| "sources": _dedupe_records(sources, key_fields=("path", "kind")), | |
| "warnings": _dedupe_preserve_order(warnings), | |
| } | |
| def _extract_config( | |
| hermes_dir: Path, | |
| state_dir: Path, | |
| sources: list[dict[str, Any]], | |
| warnings: list[str], | |
| ) -> dict[str, Any]: | |
| config: dict[str, Any] = {} | |
| yaml_files = [ | |
| path | |
| for path in ( | |
| hermes_dir / "config.yaml", | |
| hermes_dir / "dashboard" / "alerts.yaml", | |
| ) | |
| if path.exists() | |
| ] | |
| json_candidates = [ | |
| path | |
| for path in ( | |
| hermes_dir / "gateway_state.json", | |
| hermes_dir / "channel_directory.json", | |
| hermes_dir / "cron" / "jobs.json", | |
| ) | |
| if path.exists() | |
| ] | |
| for path in yaml_files: | |
| if _looks_sensitive(path): | |
| continue | |
| parsed = _parse_yaml_summary(path) | |
| if parsed: | |
| _merge_nested(config, parsed) | |
| _record_source(sources, path, kind="yaml-config", details=parsed.get("_summary", {})) | |
| # Prefer a few known configuration JSON files, but do not ingest secrets. | |
| for path in json_candidates: | |
| if _looks_sensitive(path): | |
| continue | |
| if path.name in { | |
| "config.json", | |
| "settings.json", | |
| "state.json", | |
| "runtime.json", | |
| } or "config" in path.name.lower() or "settings" in path.name.lower(): | |
| parsed = _safe_json_load(path) | |
| if isinstance(parsed, dict): | |
| summary = _summarize_json_dict(parsed) | |
| _merge_nested(config, summary) | |
| _record_source(sources, path, kind="json-config", details={"keys": sorted(summary.keys())[:12]}) | |
| elif parsed is not None: | |
| warnings.append(f"unexpected JSON config shape at {path}") | |
| config = _normalize_config(config) | |
| if not config: | |
| config = {} | |
| return config | |
| def _extract_status( | |
| hermes_dir: Path, | |
| state_dir: Path, | |
| config: dict[str, Any], | |
| sources: list[dict[str, Any]], | |
| warnings: list[str], | |
| ) -> dict[str, Any]: | |
| state_db = _find_first_file((state_dir, hermes_dir), {"state.db", "hermes.db", "db.sqlite", "state.sqlite"}) | |
| db_stats = _read_state_db(state_db, sources, warnings) | |
| session_file_count = len(list(_collect_session_files(hermes_dir, state_dir))) | |
| channel_state = _merge_channel_state(db_stats.get("channels", {}), hermes_dir / "channel_directory.json", sources) | |
| gateway_state = _merge_gateway_state(db_stats.get("gateway", {}), hermes_dir / "gateway_state.json", sources) | |
| status = { | |
| "exists": {"hermes_dir": hermes_dir.exists(), "state_dir": state_dir.exists(), "state_db": bool(state_db and state_db.exists())}, | |
| "gateway": gateway_state, | |
| "channels": channel_state, | |
| "cron": db_stats.get("cron", {}), | |
| "counts": { | |
| "sessions": db_stats.get("session_count", 0), | |
| "session_files": session_file_count, | |
| "tools": db_stats.get("tool_count", 0), | |
| "models": db_stats.get("model_count", 0), | |
| "sources": db_stats.get("source_count", 0), | |
| "channels": channel_state.get("count", 0), | |
| "profiles": db_stats.get("profile_count", 0), | |
| "skills": db_stats.get("skill_count", 0), | |
| }, | |
| "flags": { | |
| "checkpoints": _get_bool_flag(config, "checkpoints.enabled"), | |
| "smart_model_routing": _get_bool_flag(config, "smart_model_routing.enabled"), | |
| "browser_record_sessions": _get_bool_flag(config, "browser.record_sessions"), | |
| "gateway_startup_failed": bool(gateway_state.get("startup_failed")), | |
| }, | |
| } | |
| return status | |
| def _extract_extensions( | |
| hermes_dir: Path, | |
| state_dir: Path, | |
| sources: list[dict[str, Any]], | |
| warnings: list[str], | |
| ) -> dict[str, list[dict[str, Any]]]: | |
| skills: list[dict[str, Any]] = [] | |
| toolsets: list[dict[str, Any]] = [] | |
| channels: list[dict[str, Any]] = [] | |
| profiles: list[dict[str, Any]] = [] | |
| skills_snapshot = _find_first_file((hermes_dir, state_dir), {".skills_prompt_snapshot.json"}) | |
| if not skills_snapshot: | |
| # Fallback to any obvious snapshot file. | |
| for base in (hermes_dir, state_dir): | |
| candidate = _find_first_file((base,), {"skills_prompt_snapshot.json", ".skills_prompt_snapshot.json"}) | |
| if candidate: | |
| skills_snapshot = candidate | |
| break | |
| if skills_snapshot and skills_snapshot.exists(): | |
| payload = _safe_json_load(skills_snapshot) | |
| if isinstance(payload, dict): | |
| skills.extend(_summarize_skill_snapshot(payload)) | |
| _record_source(sources, skills_snapshot, kind="skills-snapshot", details={"skills": len(skills)}) | |
| else: | |
| warnings.append(f"unable to parse skills snapshot at {skills_snapshot}") | |
| skills_dir = _find_first_dir((hermes_dir, state_dir), {"skills", ".skills"}) | |
| if skills_dir: | |
| skills.extend(_summarize_skills_dir(skills_dir)) | |
| _record_source(sources, skills_dir, kind="skills-dir", details={"items": len(skills)}) | |
| state_db = _find_first_file((state_dir, hermes_dir), {"state.db", "hermes.db", "db.sqlite", "state.sqlite"}) | |
| db_stats = _read_state_db(state_db, sources, warnings) | |
| toolsets.extend(db_stats.get("toolsets", [])) | |
| channels.extend(db_stats.get("channels_list", [])) | |
| profiles.extend(db_stats.get("profiles", [])) | |
| return { | |
| "skills": _dedupe_records(skills, key_fields=("name", "path", "id")), | |
| "toolsets": _dedupe_records(toolsets, key_fields=("name", "path", "id")), | |
| "channels": _dedupe_records(channels, key_fields=("name", "state", "path")), | |
| "profiles": _dedupe_records(profiles, key_fields=("name", "path", "id")), | |
| } | |
| def _extract_usage( | |
| hermes_dir: Path, | |
| state_dir: Path, | |
| sources: list[dict[str, Any]], | |
| warnings: list[str], | |
| ) -> dict[str, Any]: | |
| state_db = _find_first_file((state_dir, hermes_dir), {"state.db", "hermes.db", "db.sqlite", "state.sqlite"}) | |
| db_stats = _read_state_db(state_db, sources, warnings) | |
| session_files = list(_collect_session_files(hermes_dir, state_dir)) | |
| session_summaries = [] | |
| for path in session_files[:50]: | |
| summary = _summarize_session_file(path) | |
| if summary: | |
| session_summaries.append(summary) | |
| _record_source(sources, path, kind="session-json", details={"events": summary.get("events"), "messages": summary.get("messages")}) | |
| prompt_counts = _count_prompt_like_artifacts(hermes_dir, state_dir) | |
| usage = { | |
| "sessions": { | |
| "db_count": db_stats.get("session_count", 0), | |
| "file_count": len(session_files), | |
| "samples": session_summaries[:MAX_SAMPLE_ITEMS], | |
| }, | |
| "tools": { | |
| "db_count": db_stats.get("tool_count", 0), | |
| "top": db_stats.get("tool_usage", [])[:MAX_SAMPLE_ITEMS], | |
| }, | |
| "models": { | |
| "db_count": db_stats.get("model_count", 0), | |
| "top": db_stats.get("model_usage", [])[:MAX_SAMPLE_ITEMS], | |
| }, | |
| "sources": { | |
| "db_count": db_stats.get("source_count", 0), | |
| "top": db_stats.get("source_usage", [])[:MAX_SAMPLE_ITEMS], | |
| }, | |
| "cron": db_stats.get("cron", {}), | |
| "prompts": prompt_counts, | |
| "observed_skills": db_stats.get("skill_usage", [])[:MAX_SAMPLE_ITEMS], | |
| } | |
| return usage | |
| def _extract_instruction_layers( | |
| hermes_dir: Path, | |
| state_dir: Path, | |
| sources: list[dict[str, Any]], | |
| warnings: list[str], | |
| ) -> list[dict[str, Any]]: | |
| layers: list[dict[str, Any]] = [] | |
| candidates = [ | |
| hermes_dir / "SOUL.md", | |
| hermes_dir / "ADHS_LEARNING_PROFILE.md", | |
| hermes_dir / "hermes-agent" / "AGENTS.md", | |
| hermes_dir / "hermes-agent" / "README.md", | |
| ] | |
| profiles_dir = hermes_dir / "profiles" | |
| if profiles_dir.exists(): | |
| for profile in sorted(profiles_dir.iterdir()): | |
| if not profile.is_dir() or _skip_dir_name(profile.name): | |
| continue | |
| for name in ("SOUL.md", "AGENTS.md", "README.md"): | |
| candidate = profile / name | |
| if candidate.exists(): | |
| candidates.append(candidate) | |
| for path in candidates: | |
| if not path.exists(): | |
| continue | |
| if _looks_sensitive(path): | |
| continue | |
| layer = _summarize_instruction_file(path) | |
| if layer: | |
| layers.append(layer) | |
| _record_source(sources, path, kind="instruction-layer", details={"kind": layer.get("kind")}) | |
| return _dedupe_records(layers, key_fields=("path", "kind", "name")) | |
| def _add_discoveries( | |
| discoveries: list[dict[str, Any]], | |
| status: dict[str, Any], | |
| config: dict[str, Any], | |
| extensions: dict[str, list[dict[str, Any]]], | |
| usage: dict[str, Any], | |
| ) -> None: | |
| channels = status.get("channels", {}) or {} | |
| gateway = status.get("gateway", {}) or {} | |
| flags = status.get("flags", {}) or {} | |
| counts = status.get("counts", {}) or {} | |
| if channels.get("count", 0) == 0: | |
| discoveries.append({"kind": "empty_channels", "message": "No channels were discovered in Hermes state."}) | |
| if gateway.get("startup_failed"): | |
| discoveries.append({"kind": "gateway_startup_failed", "message": "Hermes gateway reports startup failure.", "state": gateway}) | |
| for flag_name in ("checkpoints", "smart_model_routing", "browser_record_sessions"): | |
| if flags.get(flag_name) is False: | |
| discoveries.append({"kind": f"{flag_name}_disabled", "message": f"{flag_name} is disabled."}) | |
| skill_names = [item.get("name") for item in extensions.get("skills", []) if item.get("name")] | |
| observed_skills = {item.get("name"): item.get("count", 0) for item in usage.get("observed_skills", []) if item.get("name")} | |
| low_usage = [name for name in skill_names if observed_skills.get(name, 0) <= LOW_USAGE_SKILL_THRESHOLD] | |
| if len(skill_names) >= 8 and low_usage: | |
| discoveries.append( | |
| { | |
| "kind": "many_skills_low_usage", | |
| "message": "Many known skills have low observed usage.", | |
| "known_skills": len(skill_names), | |
| "low_usage_skills": low_usage[:MAX_SAMPLE_ITEMS], | |
| } | |
| ) | |
| if counts.get("sessions", 0) and counts.get("tools", 0) == 0: | |
| discoveries.append({"kind": "no_tool_usage", "message": "Sessions exist but no tool usage was observed."}) | |
| def _merge_gateway_state( | |
| db_gateway: dict[str, Any], | |
| gateway_path: Path, | |
| sources: list[dict[str, Any]], | |
| ) -> dict[str, Any]: | |
| gateway = dict(db_gateway or {}) | |
| payload = _safe_json_load(gateway_path) | |
| if isinstance(payload, dict): | |
| status = payload.get("status") or payload.get("state") or payload.get("gateway_state") | |
| if status and "status" not in gateway: | |
| gateway["status"] = _scrub_text(status) | |
| error = payload.get("last_error") or payload.get("exit_reason") | |
| if error and "last_error" not in gateway: | |
| gateway["last_error"] = _scrub_text(error) | |
| lowered = " ".join( | |
| str(payload.get(key, "")) | |
| for key in ("status", "state", "gateway_state", "last_error", "exit_reason") | |
| ).lower() | |
| platforms = payload.get("platforms") | |
| if isinstance(platforms, dict): | |
| for item in platforms.values(): | |
| if isinstance(item, dict): | |
| lowered += " " + " ".join(str(item.get(key, "")) for key in ("state", "error_message", "error_code")).lower() | |
| if "failed" in lowered or "error" in lowered: | |
| gateway["startup_failed"] = True | |
| _record_source(sources, gateway_path, kind="gateway-state", details={"keys": sorted(payload.keys())[:12]}) | |
| gateway.setdefault("startup_failed", False) | |
| return gateway | |
| def _merge_channel_state( | |
| db_channels: dict[str, Any], | |
| channels_path: Path, | |
| sources: list[dict[str, Any]], | |
| ) -> dict[str, Any]: | |
| channels = dict(db_channels or {}) | |
| payload = _safe_json_load(channels_path) | |
| if isinstance(payload, dict): | |
| platform_counts = {} | |
| total = 0 | |
| for name, entries in payload.items(): | |
| if isinstance(entries, list): | |
| platform_counts[name] = len(entries) | |
| total += len(entries) | |
| channels["platform_counts"] = platform_counts | |
| channels["count"] = max(int(channels.get("count") or 0), total) | |
| channels["empty_platforms"] = [name for name, count in platform_counts.items() if count == 0] | |
| _record_source(sources, channels_path, kind="channel-directory", details={"platforms": len(platform_counts)}) | |
| channels.setdefault("count", 0) | |
| return channels | |
| def _read_state_db( | |
| path: Path | None, | |
| sources: list[dict[str, Any]], | |
| warnings: list[str], | |
| ) -> dict[str, Any]: | |
| if not path or not path.exists(): | |
| return {} | |
| try: | |
| conn = sqlite3.connect(f"file:{path}?mode=ro&immutable=1", uri=True) | |
| except sqlite3.Error as exc: | |
| warnings.append(f"unable to open state db {path}: {exc}") | |
| return {} | |
| conn.row_factory = sqlite3.Row | |
| stats: dict[str, Any] = {} | |
| try: | |
| stats["session_count"] = _count_rows(conn, ("sessions", "session")) | |
| stats["tool_count"] = _count_rows(conn, ("tools", "tool_usage", "session_tools")) | |
| stats["model_count"] = _count_rows(conn, ("models", "model_usage", "session_models")) | |
| stats["source_count"] = _count_rows(conn, ("sources", "source_usage")) | |
| stats["profile_count"] = _count_rows(conn, ("profiles", "profile")) | |
| stats["skill_count"] = _count_rows(conn, ("skills", "skill")) | |
| stats["cron"] = _read_cron_state(conn) | |
| stats["gateway"] = _read_gateway_state(conn) | |
| stats["channels"] = _read_channel_state(conn) | |
| stats["channels_list"] = _read_channels_list(conn) | |
| stats["toolsets"] = _read_named_inventory(conn, ("toolsets", "toolset")) | |
| stats["profiles"] = _read_named_inventory(conn, ("profiles", "profile")) | |
| stats["tool_usage"] = _read_ranked_usage(conn, ("tool_usage", "tools", "session_tools"), label="tool") | |
| stats["model_usage"] = _read_ranked_usage(conn, ("model_usage", "models", "session_models"), label="model") | |
| stats["source_usage"] = _read_ranked_usage(conn, ("source_usage", "sources"), label="source") | |
| stats["skill_usage"] = _read_ranked_usage(conn, ("skill_usage", "skills"), label="skill") | |
| for key, value in _read_core_session_stats(conn).items(): | |
| if value not in (None, "", [], {}, 0) or stats.get(key) in (None, "", [], {}, 0): | |
| stats[key] = value | |
| _record_source(sources, path, kind="state-db", details={"tables": _table_names(conn)[:12]}) | |
| except sqlite3.Error as exc: | |
| warnings.append(f"unable to query state db {path}: {exc}") | |
| finally: | |
| conn.close() | |
| return stats | |
| def _read_core_session_stats(conn: sqlite3.Connection) -> dict[str, Any]: | |
| stats: dict[str, Any] = {} | |
| tables = set(_table_names(conn)) | |
| if "sessions" in tables: | |
| stats["session_count"] = _scalar_int(conn, "SELECT COUNT(*) FROM sessions") | |
| stats["tool_count"] = _scalar_int(conn, "SELECT COALESCE(SUM(tool_call_count), 0) FROM sessions") | |
| stats["model_count"] = _scalar_int(conn, "SELECT COUNT(DISTINCT model) FROM sessions WHERE model IS NOT NULL") | |
| stats["source_count"] = _scalar_int(conn, "SELECT COUNT(DISTINCT source) FROM sessions WHERE source IS NOT NULL") | |
| stats["cron"] = {"count": _scalar_int(conn, "SELECT COUNT(*) FROM sessions WHERE source = 'cron'")} | |
| stats["model_usage"] = _query_name_counts(conn, "SELECT model, COUNT(*) FROM sessions WHERE model IS NOT NULL GROUP BY model ORDER BY COUNT(*) DESC, model LIMIT 20") | |
| stats["source_usage"] = _query_name_counts(conn, "SELECT source, COUNT(*) FROM sessions WHERE source IS NOT NULL GROUP BY source ORDER BY COUNT(*) DESC, source LIMIT 20") | |
| if "messages" in tables: | |
| message_tool_count = _scalar_int(conn, "SELECT COUNT(*) FROM messages WHERE tool_name IS NOT NULL AND tool_name != ''") | |
| if message_tool_count: | |
| stats["tool_count"] = max(int(stats.get("tool_count") or 0), message_tool_count) | |
| stats["tool_usage"] = _query_name_counts(conn, "SELECT tool_name, COUNT(*) FROM messages WHERE tool_name IS NOT NULL AND tool_name != '' GROUP BY tool_name ORDER BY COUNT(*) DESC, tool_name LIMIT 30") | |
| return stats | |
| def _scalar_int(conn: sqlite3.Connection, query: str) -> int: | |
| try: | |
| row = conn.execute(query).fetchone() | |
| return int(row[0] or 0) if row else 0 | |
| except sqlite3.Error: | |
| return 0 | |
| def _query_name_counts(conn: sqlite3.Connection, query: str) -> list[dict[str, Any]]: | |
| try: | |
| rows = conn.execute(query).fetchall() | |
| except sqlite3.Error: | |
| return [] | |
| return [{"name": _scrub_text(row[0]), "count": int(row[1] or 0)} for row in rows if row and row[0]] | |
| def _read_cron_state(conn: sqlite3.Connection) -> dict[str, Any]: | |
| tables = _table_names(conn) | |
| result: dict[str, Any] = {"count": 0} | |
| for table in tables: | |
| if "cron" not in table.lower(): | |
| continue | |
| rows = _safe_select_all(conn, table, limit=50) | |
| result["count"] += len(rows) | |
| result.setdefault("tables", []).append({"name": table, "rows": len(rows)}) | |
| return result | |
| def _read_gateway_state(conn: sqlite3.Connection) -> dict[str, Any]: | |
| tables = _table_names(conn) | |
| gateway: dict[str, Any] = {} | |
| for table in tables: | |
| if "gateway" not in table.lower(): | |
| continue | |
| rows = _safe_select_all(conn, table, limit=10) | |
| if rows: | |
| gateway["tables"] = gateway.get("tables", []) + [{"name": table, "rows": len(rows)}] | |
| first = rows[0] | |
| if isinstance(first, dict): | |
| for key in ("state", "status", "startup_failed", "last_error", "provider", "model"): | |
| if key in first and key not in gateway: | |
| gateway[key] = _scrub_value(first.get(key)) | |
| if "startup_failed" not in gateway: | |
| for table in tables: | |
| if "gateway" not in table.lower(): | |
| continue | |
| rows = _safe_select_all(conn, table, limit=10) | |
| for row in rows: | |
| if isinstance(row, dict): | |
| status = str(row.get("status", row.get("state", ""))).lower() | |
| if "failed" in status: | |
| gateway["startup_failed"] = True | |
| break | |
| gateway.setdefault("startup_failed", False) | |
| return gateway | |
| def _read_channel_state(conn: sqlite3.Connection) -> dict[str, Any]: | |
| channels: dict[str, Any] = {"count": 0} | |
| tables = _table_names(conn) | |
| for table in tables: | |
| if "channel" not in table.lower(): | |
| continue | |
| rows = _safe_select_all(conn, table, limit=100) | |
| channels["count"] += len(rows) | |
| channels.setdefault("tables", []).append({"name": table, "rows": len(rows)}) | |
| return channels | |
| def _read_channels_list(conn: sqlite3.Connection) -> list[dict[str, Any]]: | |
| results: list[dict[str, Any]] = [] | |
| for table in _table_names(conn): | |
| if "channel" not in table.lower(): | |
| continue | |
| for row in _safe_select_all(conn, table, limit=200): | |
| if isinstance(row, dict): | |
| results.append( | |
| { | |
| "name": _scrub_text(row.get("name") or row.get("channel") or row.get("id")), | |
| "state": _scrub_text(row.get("state") or row.get("status")), | |
| "path": _scrub_text(row.get("path") or row.get("directory")), | |
| } | |
| ) | |
| return [item for item in results if item.get("name")] | |
| def _read_named_inventory(conn: sqlite3.Connection, table_names: Iterable[str]) -> list[dict[str, Any]]: | |
| inventory: list[dict[str, Any]] = [] | |
| tables = _table_names(conn) | |
| for table in tables: | |
| if not any(candidate in table.lower() for candidate in table_names): | |
| continue | |
| for row in _safe_select_all(conn, table, limit=200): | |
| if isinstance(row, dict): | |
| name = row.get("name") or row.get("id") or row.get("toolset") or row.get("profile") | |
| inventory.append( | |
| { | |
| "name": _scrub_text(name), | |
| "path": _scrub_text(row.get("path") or row.get("directory")), | |
| "state": _scrub_text(row.get("state") or row.get("status")), | |
| } | |
| ) | |
| return [item for item in inventory if item.get("name")] | |
| def _read_ranked_usage(conn: sqlite3.Connection, table_names: Iterable[str], label: str) -> list[dict[str, Any]]: | |
| ranked: dict[str, int] = {} | |
| tables = _table_names(conn) | |
| for table in tables: | |
| if not any(candidate in table.lower() for candidate in table_names): | |
| continue | |
| rows = _safe_select_all(conn, table, limit=500) | |
| for row in rows: | |
| if not isinstance(row, dict): | |
| continue | |
| name = ( | |
| row.get("name") | |
| or row.get(f"{label}_name") | |
| or row.get(label) | |
| or row.get("id") | |
| or row.get("source") | |
| ) | |
| if not name: | |
| continue | |
| count = row.get("count") or row.get("uses") or row.get("usage_count") or row.get("n") or 1 | |
| try: | |
| ranked[str(name)] = ranked.get(str(name), 0) + int(count) | |
| except (TypeError, ValueError): | |
| ranked[str(name)] = ranked.get(str(name), 0) + 1 | |
| return [ | |
| {"name": name, "count": count} | |
| for name, count in sorted(ranked.items(), key=lambda item: (-item[1], item[0].lower())) | |
| ] | |
| def _safe_select_all(conn: sqlite3.Connection, table: str, limit: int = 50) -> list[dict[str, Any]]: | |
| try: | |
| cursor = conn.execute(f'SELECT * FROM "{table}" LIMIT ?', (limit,)) | |
| except sqlite3.Error: | |
| return [] | |
| rows: list[dict[str, Any]] = [] | |
| for row in cursor.fetchall(): | |
| if isinstance(row, sqlite3.Row): | |
| rows.append({key: _scrub_value(row[key]) for key in row.keys()}) | |
| return rows | |
| def _count_rows(conn: sqlite3.Connection, candidates: Iterable[str]) -> int: | |
| for table in _table_names(conn): | |
| if table.lower() not in {candidate.lower() for candidate in candidates} and not any(candidate.lower() == table.lower() for candidate in candidates): | |
| if not any(candidate in table.lower() for candidate in candidates): | |
| continue | |
| try: | |
| cursor = conn.execute(f'SELECT COUNT(*) FROM "{table}"') | |
| row = cursor.fetchone() | |
| if row: | |
| return int(row[0]) | |
| except sqlite3.Error: | |
| continue | |
| return 0 | |
| def _table_names(conn: sqlite3.Connection) -> list[str]: | |
| try: | |
| cursor = conn.execute("SELECT name FROM sqlite_master WHERE type='table' ORDER BY name") | |
| except sqlite3.Error: | |
| return [] | |
| return [str(row[0]) for row in cursor.fetchall() if row and row[0]] | |
| def _collect_session_files(hermes_dir: Path, state_dir: Path) -> Iterable[Path]: | |
| seen: set[Path] = set() | |
| for base in (hermes_dir, state_dir): | |
| if not base.exists(): | |
| continue | |
| for path in _walk_files(base): | |
| if path.suffix != ".json" or _looks_sensitive(path): | |
| continue | |
| if "session" in path.name.lower() or "conversation" in path.name.lower() or "run" in path.name.lower(): | |
| try: | |
| resolved = path.resolve() | |
| except OSError: | |
| continue | |
| if resolved not in seen: | |
| seen.add(resolved) | |
| yield path | |
| def _summarize_session_file(path: Path) -> dict[str, Any] | None: | |
| data = _safe_json_load(path) | |
| if not isinstance(data, dict): | |
| return None | |
| summary: dict[str, Any] = { | |
| "path": str(path), | |
| "keys": sorted(k for k in data.keys() if not _is_secret_key(k))[:20], | |
| } | |
| if "id" in data: | |
| summary["id"] = _scrub_value(data.get("id")) | |
| if "model" in data: | |
| summary["model"] = _scrub_value(data.get("model")) | |
| if "provider" in data: | |
| summary["provider"] = _scrub_value(data.get("provider")) | |
| if isinstance(data.get("messages"), list): | |
| summary["messages"] = len(data["messages"]) | |
| if isinstance(data.get("events"), list): | |
| summary["events"] = len(data["events"]) | |
| if isinstance(data.get("turns"), list): | |
| summary["turns"] = len(data["turns"]) | |
| summary["preview"] = _summarize_json_shape(data) | |
| return summary | |
| def _count_prompt_like_artifacts(hermes_dir: Path, state_dir: Path) -> dict[str, Any]: | |
| counts = {"files": 0, "bytes": 0} | |
| for base in (hermes_dir, state_dir): | |
| if not base.exists(): | |
| continue | |
| for path in _walk_files(base): | |
| if _looks_sensitive(path): | |
| continue | |
| if any(token in path.name.lower() for token in ("prompt", "instruction", "snapshot")): | |
| counts["files"] += 1 | |
| try: | |
| counts["bytes"] += path.stat().st_size | |
| except OSError: | |
| continue | |
| return counts | |
| def _summarize_skill_snapshot(payload: dict[str, Any]) -> list[dict[str, Any]]: | |
| skills: list[dict[str, Any]] = [] | |
| for key in ("skills", "items", "entries"): | |
| value = payload.get(key) | |
| if isinstance(value, list): | |
| for item in value: | |
| if not isinstance(item, dict): | |
| continue | |
| name = item.get("name") or item.get("skill_name") or item.get("skill") or item.get("id") | |
| skills.append( | |
| { | |
| "name": _scrub_text(name), | |
| "path": _scrub_text(item.get("path")), | |
| "category": _scrub_text(item.get("category")), | |
| "summary": _clip_text(item.get("summary") or item.get("description")), | |
| "version": _scrub_text(item.get("version")), | |
| } | |
| ) | |
| if not skills and isinstance(payload.get("snapshot"), list): | |
| for item in payload["snapshot"]: | |
| if isinstance(item, dict): | |
| skills.append({"name": _scrub_text(item.get("name")), "summary": _clip_text(item.get("summary"))}) | |
| return [item for item in skills if item.get("name")] | |
| def _summarize_skills_dir(skills_dir: Path) -> list[dict[str, Any]]: | |
| entries: list[dict[str, Any]] = [] | |
| try: | |
| for path in skills_dir.iterdir(): | |
| if _looks_sensitive(path): | |
| continue | |
| if path.is_dir(): | |
| entries.append({"name": path.name, "path": str(path), "kind": "dir"}) | |
| elif path.is_file(): | |
| entries.append({"name": path.stem, "path": str(path), "kind": "file", "size": _safe_size(path)}) | |
| except OSError: | |
| return entries | |
| return entries | |
| def _summarize_instruction_file(path: Path) -> dict[str, Any] | None: | |
| text = _safe_read_text(path) | |
| if text is None: | |
| return None | |
| summary = { | |
| "path": str(path), | |
| "kind": _infer_instruction_kind(path, text), | |
| "name": path.name, | |
| "lines": len(text.splitlines()), | |
| "preview": _clip_text(_first_meaningful_lines(text)), | |
| } | |
| return summary | |
| def _parse_yaml_summary(path: Path) -> dict[str, Any]: | |
| text = _safe_read_text(path) | |
| if text is None: | |
| return {} | |
| root: dict[str, Any] = {} | |
| stack: list[tuple[int, dict[str, Any]]] = [(-1, root)] | |
| for raw_line in text.splitlines(): | |
| indent = len(raw_line) - len(raw_line.lstrip(" ")) | |
| stripped = raw_line.strip() | |
| if not stripped or stripped.startswith("#"): | |
| continue | |
| if stripped.startswith("- "): | |
| # The parser only builds line-based summaries, not full YAML arrays. | |
| continue | |
| match = re.match(r"^([A-Za-z0-9_.-]+)\s*:\s*(.*)$", stripped) | |
| if not match: | |
| continue | |
| key, value = match.group(1), match.group(2).strip() | |
| while len(stack) > 1 and indent <= stack[-1][0]: | |
| stack.pop() | |
| current = stack[-1][1] | |
| if value == "": | |
| current[key] = {} | |
| stack.append((indent, current[key])) | |
| continue | |
| if value.lower() in {"true", "false"}: | |
| current[key] = value.lower() == "true" | |
| elif re.fullmatch(r"-?\d+", value): | |
| current[key] = int(value) | |
| elif re.fullmatch(r"-?\d+\.\d+", value): | |
| current[key] = float(value) | |
| else: | |
| current[key] = _scrub_text(_strip_yaml_quotes(value)) | |
| summary = {k: v for k, v in root.items() if not _is_secret_key(k)} | |
| summary["_summary"] = { | |
| "keys": sorted(k for k in summary.keys() if k != "_summary")[:20], | |
| "path": str(path), | |
| "lines": len(text.splitlines()), | |
| } | |
| return summary | |
| def _normalize_config(config: dict[str, Any]) -> dict[str, Any]: | |
| normalized = {} | |
| for key, value in config.items(): | |
| if key == "_summary": | |
| continue | |
| normalized[key] = value | |
| flat = {} | |
| for key in ("checkpoints", "smart_model_routing", "browser", "model", "provider", "fallbacks"): | |
| if key in normalized: | |
| flat[key] = normalized[key] | |
| for key in ("default_model", "default_provider"): | |
| if key in normalized: | |
| flat[key] = normalized[key] | |
| if "browser" in normalized and isinstance(normalized["browser"], dict): | |
| browser = normalized["browser"] | |
| flat["browser"] = { | |
| "record_sessions": browser.get("record_sessions"), | |
| } | |
| for key in normalized: | |
| if key not in flat: | |
| flat[key] = normalized[key] | |
| return flat | |
| def _get_bool_flag(config: dict[str, Any], dotted_key: str) -> bool | None: | |
| parts = dotted_key.split(".") | |
| current: Any = config | |
| for part in parts: | |
| if isinstance(current, dict) and part in current: | |
| current = current[part] | |
| else: | |
| return None | |
| if isinstance(current, bool): | |
| return current | |
| if isinstance(current, str): | |
| lowered = current.lower() | |
| if lowered in {"true", "yes", "on", "1"}: | |
| return True | |
| if lowered in {"false", "no", "off", "0"}: | |
| return False | |
| return None | |
| def _find_files(base: Path, suffixes: set[str]) -> list[Path]: | |
| if not base.exists(): | |
| return [] | |
| result: list[Path] = [] | |
| for path in _walk_files(base): | |
| if path.suffix in suffixes or path.name in suffixes: | |
| result.append(path) | |
| return result | |
| def _find_first_file(bases: Iterable[Path], names: set[str]) -> Path | None: | |
| for base in bases: | |
| if not base.exists(): | |
| continue | |
| for name in names: | |
| candidate = base / name | |
| if candidate.is_file(): | |
| return candidate | |
| for path in _walk_files(base): | |
| if path.name in names: | |
| return path | |
| return None | |
| def _find_first_dir(bases: Iterable[Path], names: set[str]) -> Path | None: | |
| for base in bases: | |
| if not base.exists(): | |
| continue | |
| for name in names: | |
| candidate = base / name | |
| if candidate.is_dir(): | |
| return candidate | |
| for root, dirs, _files in os.walk(base): | |
| dirs[:] = [name for name in dirs if not _skip_dir_name(name)] | |
| for dirname in dirs: | |
| if dirname in names: | |
| return Path(root) / dirname | |
| return None | |
| def _walk_files(base: Path) -> Iterable[Path]: | |
| try: | |
| for root, dirs, files in os.walk(base): | |
| dirs[:] = [name for name in dirs if not _skip_dir_name(name)] | |
| for filename in files: | |
| path = Path(root) / filename | |
| if not _skip_path(path): | |
| yield path | |
| except OSError: | |
| return | |
| def _skip_dir_name(name: str) -> bool: | |
| return name in SKIP_DIR_NAMES or name.endswith(".egg-info") | |
| def _skip_path(path: Path) -> bool: | |
| return any(_skip_dir_name(part) for part in path.parts) | |
| def _safe_json_load(path: Path) -> Any | None: | |
| text = _safe_read_text(path) | |
| if text is None: | |
| return None | |
| try: | |
| return json.loads(text) | |
| except json.JSONDecodeError: | |
| return None | |
| def _safe_read_text(path: Path) -> str | None: | |
| try: | |
| return path.read_text(encoding="utf-8", errors="replace") | |
| except OSError: | |
| return None | |
| def _safe_size(path: Path) -> int | None: | |
| try: | |
| return path.stat().st_size | |
| except OSError: | |
| return None | |
| def _record_source( | |
| sources: list[dict[str, Any]], | |
| path: Path, | |
| *, | |
| kind: str, | |
| details: dict[str, Any] | None = None, | |
| ) -> None: | |
| sources.append( | |
| { | |
| "path": str(path), | |
| "kind": kind, | |
| "size": _safe_size(path), | |
| "details": details or {}, | |
| } | |
| ) | |
| def _looks_sensitive(path: Path) -> bool: | |
| name = path.name.lower() | |
| return any(token in name for token in (".env", "token", "secret", "auth", "cookie", "credential", "password")) | |
| def _is_secret_key(key: str) -> bool: | |
| lowered = key.lower() | |
| return any(token in lowered for token in ("secret", "token", "password", "cookie", "auth", "apikey", "api_key")) | |
| def _scrub_value(value: Any) -> Any: | |
| if isinstance(value, dict): | |
| return {k: _scrub_value(v) for k, v in value.items() if not _is_secret_key(str(k))} | |
| if isinstance(value, list): | |
| return [_scrub_value(v) for v in value[:MAX_SAMPLE_ITEMS]] | |
| if isinstance(value, str): | |
| return _scrub_text(value) | |
| return value | |
| def _scrub_text(value: Any) -> Any: | |
| if value is None: | |
| return None | |
| text = str(value) | |
| if _is_secret_key(text) or _looks_like_secret_value(text): | |
| return "[redacted]" | |
| return _clip_text(text) | |
| def _clip_text(text: str) -> str: | |
| text = text.strip() | |
| if len(text) <= MAX_TEXT_PREVIEW: | |
| return text | |
| return text[: MAX_TEXT_PREVIEW - 3].rstrip() + "..." | |
| def _first_meaningful_lines(text: str, limit: int = 8) -> str: | |
| lines = [] | |
| for raw in text.splitlines(): | |
| stripped = raw.strip() | |
| if not stripped: | |
| continue | |
| if stripped.startswith("#"): | |
| continue | |
| if _is_secret_key(stripped): | |
| continue | |
| lines.append(stripped) | |
| if len(lines) >= limit: | |
| break | |
| return "\n".join(lines) | |
| def _infer_instruction_kind(path: Path, text: str) -> str: | |
| name = path.name.lower() | |
| if "system" in name: | |
| return "system" | |
| if "instruction" in name: | |
| return "instruction" | |
| if "prompt" in name: | |
| return "prompt" | |
| if path.suffix in {".yaml", ".yml"}: | |
| return "config" | |
| if "skill" in name: | |
| return "skill" | |
| return "text" | |
| def _summarize_json_dict(data: dict[str, Any]) -> dict[str, Any]: | |
| result: dict[str, Any] = {} | |
| for key, value in data.items(): | |
| if _is_secret_key(str(key)): | |
| continue | |
| if key in {"instruction", "prompt", "system_prompt", "request", "messages", "events", "conversation"}: | |
| continue | |
| if isinstance(value, dict): | |
| result[key] = _summarize_json_dict(value) | |
| elif isinstance(value, list): | |
| result[key] = _summarize_json_list(value) | |
| else: | |
| result[key] = _scrub_value(value) | |
| return result | |
| def _summarize_json_list(values: list[Any]) -> list[Any]: | |
| summarized = [] | |
| for item in values[:MAX_SAMPLE_ITEMS]: | |
| if isinstance(item, dict): | |
| summarized.append(_summarize_json_dict(item)) | |
| elif isinstance(item, list): | |
| summarized.append(_summarize_json_list(item)) | |
| else: | |
| summarized.append(_scrub_value(item)) | |
| return summarized | |
| def _summarize_json_shape(data: dict[str, Any]) -> dict[str, Any]: | |
| return { | |
| "keys": sorted(k for k in data.keys() if not _is_secret_key(k))[:20], | |
| "lists": sorted(k for k, v in data.items() if isinstance(v, list) and not _is_secret_key(k))[:20], | |
| "dicts": sorted(k for k, v in data.items() if isinstance(v, dict) and not _is_secret_key(k))[:20], | |
| } | |
| def _dedupe_records(items: list[dict[str, Any]], *, key_fields: tuple[str, ...]) -> list[dict[str, Any]]: | |
| seen: set[tuple[Any, ...]] = set() | |
| deduped: list[dict[str, Any]] = [] | |
| for item in items: | |
| key = tuple(item.get(field) for field in key_fields) | |
| if key in seen: | |
| continue | |
| seen.add(key) | |
| deduped.append(item) | |
| return deduped | |
| def _merge_nested(target: dict[str, Any], source: dict[str, Any]) -> None: | |
| for key, value in source.items(): | |
| if key == "_summary": | |
| continue | |
| if key not in target: | |
| target[key] = value | |
| continue | |
| if isinstance(target[key], dict) and isinstance(value, dict): | |
| _merge_nested(target[key], value) | |
| elif isinstance(target[key], list) and isinstance(value, list): | |
| target[key].extend(v for v in value if v not in target[key]) | |
| def _normalize_value(value: Any) -> Any: | |
| if isinstance(value, dict): | |
| return {k: _normalize_value(v) for k, v in value.items()} | |
| if isinstance(value, list): | |
| return [_normalize_value(v) for v in value] | |
| return value | |
| def _strip_yaml_quotes(value: str) -> str: | |
| if len(value) >= 2 and value[0] == value[-1] and value[0] in {'"', "'"}: | |
| return value[1:-1] | |
| return value | |
| def _looks_like_secret_value(text: str) -> bool: | |
| lowered = text.lower().strip() | |
| if not lowered: | |
| return False | |
| if any(token in lowered for token in ("bearer ", "api_key", "access_token", "refresh_token", "secret", "password")): | |
| return True | |
| if "private key" in lowered or "BEGIN PRIVATE KEY" in text: | |
| return True | |
| if len(text) >= 24 and " " not in text and any(ch.isdigit() for ch in text) and any(ch.isalpha() for ch in text): | |
| if re.fullmatch(r"[A-Za-z0-9._\-+/=]+", text): | |
| return True | |
| return False | |
| def _dedupe_preserve_order(values: list[str]) -> list[str]: | |
| seen = set() | |
| result = [] | |
| for value in values: | |
| if value in seen: | |
| continue | |
| seen.add(value) | |
| result.append(value) | |
| return result | |