Spaces:
Sleeping
Sleeping
| set -e | |
| BOOT_START=$(date +%s) | |
| echo "[entrypoint] HermesFace β Hermes Agent on HuggingFace Spaces" | |
| echo "[entrypoint] ====================================================" | |
| # Fail before restore, patching, or process launch when execution-critical | |
| # configuration is malformed. Error messages contain variable names only. | |
| python3 /opt/data/scripts/validate_startup_configuration.py | |
| HERMES_HOME="/opt/data" | |
| INSTALL_DIR="/opt/hermes" | |
| # ββ DNS pre-resolution (background β non-blocking) ββββββββββββββββββββββββ | |
| # Resolves Telegram / WhatsApp / Discord domains via DoH when HF Spaces | |
| # system DNS refuses them. Writes /tmp/dns-resolved.json for dns-fix.cjs | |
| # and appends /etc/hosts for Python processes. | |
| echo "[entrypoint] Starting DNS resolution in background..." | |
| python3 /opt/data/scripts/dns-resolve.py /tmp/dns-resolved.json 2>&1 & | |
| DNS_PID=$! | |
| echo "[entrypoint] DNS resolver PID: $DNS_PID" | |
| # Enable Node.js DNS fix preload for playwright / whatsapp-bridge / web build. | |
| export NODE_OPTIONS="${NODE_OPTIONS:+$NODE_OPTIONS }--require /opt/data/scripts/dns-fix.cjs" | |
| # ββ Activate virtual environment βββββββββββββββββββββββββββββββββββββββββ | |
| if [ -f "${INSTALL_DIR}/.venv/bin/activate" ]; then | |
| source "${INSTALL_DIR}/.venv/bin/activate" | |
| echo "[entrypoint] Activated venv: $(which python3)" | |
| fi | |
| # ββ Ensure data directories βββββββββββββββββββββββββββββββββββββββββββββ | |
| mkdir -p "$HERMES_HOME"/{cron,sessions,logs,hooks,memories,skills,skins,plans,workspace,home} | |
| # ββ Bootstrap config files βββββββββββββββββββββββββββββββββββββββββββββββ | |
| if [ ! -f "$HERMES_HOME/.env" ] && [ -f "$INSTALL_DIR/.env.example" ]; then | |
| cp "$INSTALL_DIR/.env.example" "$HERMES_HOME/.env" | |
| echo "[entrypoint] Created .env from example" | |
| fi | |
| if [ ! -f "$HERMES_HOME/config.yaml" ] && [ -f "$INSTALL_DIR/cli-config.yaml.example" ]; then | |
| cp "$INSTALL_DIR/cli-config.yaml.example" "$HERMES_HOME/config.yaml" | |
| echo "[entrypoint] Created config.yaml from example" | |
| fi | |
| if [ ! -f "$HERMES_HOME/SOUL.md" ] && [ -f "$INSTALL_DIR/docker/SOUL.md" ]; then | |
| cp "$INSTALL_DIR/docker/SOUL.md" "$HERMES_HOME/SOUL.md" | |
| echo "[entrypoint] Created SOUL.md from template" | |
| fi | |
| # ββ Configure dashboard basic auth (required before binding 0.0.0.0) βββββ | |
| # Hermes Agent refuses to expose the dashboard publicly with no auth | |
| # provider registered. If HERMES_ADMIN_PASSWORD is set as a Space secret, | |
| # write it into config.yaml as a hashed basic_auth credential. | |
| if [ -n "$HERMES_ADMIN_PASSWORD" ]; then | |
| python3 - <<'PYEOF' || echo "[entrypoint] WARNING: failed to configure dashboard auth (see error above) β dashboard may refuse to start" | |
| import os, sys | |
| import yaml | |
| cfg_path = "/opt/data/config.yaml" | |
| try: | |
| from plugins.dashboard_auth.basic import hash_password | |
| except Exception as e: | |
| print(f"[entrypoint] Could not import hash_password: {e}") | |
| sys.exit(1) | |
| with open(cfg_path) as f: | |
| cfg = yaml.safe_load(f) or {} | |
| username = os.environ.get("HERMES_ADMIN_USERNAME", "admin") | |
| password = os.environ["HERMES_ADMIN_PASSWORD"] | |
| cfg.setdefault("dashboard", {}) | |
| cfg["dashboard"].setdefault("basic_auth", {}) | |
| cfg["dashboard"]["basic_auth"]["username"] = username | |
| cfg["dashboard"]["basic_auth"]["password_hash"] = hash_password(password) | |
| with open(cfg_path, "w") as f: | |
| yaml.safe_dump(cfg, f, default_flow_style=False) | |
| print(f"[entrypoint] Dashboard basic auth configured for user '{username}'") | |
| PYEOF | |
| else | |
| echo "[entrypoint] WARNING: HERMES_ADMIN_PASSWORD not set as a Space secret β dashboard will refuse to bind to 0.0.0.0 and Hermes will exit." | |
| fi | |
| # ββ Sync bundled skills ββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| if [ -d "$INSTALL_DIR/skills" ] && [ -f "$INSTALL_DIR/tools/skills_sync.py" ]; then | |
| python3 "$INSTALL_DIR/tools/skills_sync.py" 2>&1 || echo "[entrypoint] Skills sync skipped" | |
| fi | |
| # ββ Build artifacts check βββββββββββββββββββββββββββββββββββββββββββββββ | |
| echo "[entrypoint] Build artifacts check:" | |
| test -f "$INSTALL_DIR/run_agent.py" && echo " OK run_agent.py" || echo " INFO: run_agent.py not found" | |
| test -f "$INSTALL_DIR/gateway/run.py" && echo " OK gateway/run.py" || echo " INFO: gateway/run.py not found" | |
| test -d "$INSTALL_DIR/web" && echo " OK web/ dashboard" || echo " INFO: web/ not found" | |
| command -v hermes >/dev/null 2>&1 && echo " OK hermes CLI: $(which hermes)" || echo " INFO: hermes CLI not in PATH" | |
| # Create logs | |
| mkdir -p /opt/data/logs | |
| touch /opt/data/logs/app.log | |
| ENTRYPOINT_END=$(date +%s) | |
| echo "[TIMER] Entrypoint (before sync_hf.py): $((ENTRYPOINT_END - BOOT_START))s" | |
| # ββ Start Hermes via sync_hf.py (handles persistence + process management) | |
| echo "[entrypoint] Starting Hermes Agent via sync_hf.py..." | |
| exec python3 -u /opt/data/scripts/sync_hf.py | |