Spaces:
Runtime error
Runtime error
| # Centralized Logging Configuration (Bug #18) | |
| export LOG_LEVEL=${LOG_LEVEL:-"info"} | |
| export LOG_FILE=${LOG_FILE:-"/app/verdant_claw.log"} | |
| # Mask sensitive env vars in logs (Bug #13) | |
| log() { | |
| local msg=$(echo "$1" | sed -E 's/(nvapi|sk|gsk)[a-zA-Z0-9]+/\1*****/g') | |
| echo "[$(date -u +"%Y-%m-%dT%H:%M:%SZ")] [$LOG_LEVEL] $msg" | tee -a $LOG_FILE | |
| } | |
| # Trap SIGTERM for graceful shutdown (Bug #12) | |
| cleanup() { | |
| log "Shutting down services gracefully..." | |
| kill $(jobs -p) 2>/dev/null | |
| sleep 2 | |
| log "Shutdown complete" | |
| exit 0 | |
| } | |
| trap cleanup SIGTERM SIGINT | |
| # Parse API_KEYS_JSON secret (Bug #9) | |
| # Supports multi-key rotation: "nvidia_2" β NVIDIA_API_KEY_2 | |
| if [ -n "$API_KEYS_JSON" ]; then | |
| log "Parsing API keys from JSON..." | |
| # Primary keys | |
| export NVIDIA_API_KEY=$(echo $API_KEYS_JSON | jq -r '.nvidia // empty') | |
| export OPENAI_API_KEY=$(echo $API_KEYS_JSON | jq -r '.openai // empty') | |
| export ANTHROPIC_API_KEY=$(echo $API_KEYS_JSON | jq -r '.anthropic // empty') | |
| export GOOGLE_API_KEY=$(echo $API_KEYS_JSON | jq -r '.google // empty') | |
| export GROQ_API_KEY=$(echo $API_KEYS_JSON | jq -r '.groq // empty') | |
| # Rotation keys (nvidia_2, openai_2, etc.) | |
| for provider in nvidia openai anthropic google groq; do | |
| for i in $(seq 2 5); do | |
| val=$(echo $API_KEYS_JSON | jq -r ".${provider}_${i} // empty") | |
| if [ -n "$val" ] && [ "$val" != "null" ]; then | |
| envname=$(echo "${provider}_API_KEY_${i}" | tr '[:lower:]' '[:upper:]') | |
| export "$envname=$val" | |
| log "β Loaded rotation key: $envname" | |
| fi | |
| done | |
| done | |
| log "β API keys loaded from JSON" | |
| else | |
| log "β οΈ WARNING: API_KEYS_JSON not set!" | |
| fi | |
| # Function to start service with retry (Bug #15) | |
| start_with_retry() { | |
| local name=$1 | |
| local cmd=$2 | |
| local max_attempts=3 | |
| for i in $(seq 1 $max_attempts); do | |
| log "Starting $name (attempt $i/$max_attempts)..." | |
| eval "$cmd" & | |
| local pid=$! | |
| sleep 5 | |
| if ps -p $pid > /dev/null; then | |
| log "β $name started (PID: $pid)" | |
| return 0 | |
| fi | |
| log "β οΈ $name failed to start, retrying..." | |
| done | |
| log "β ERROR: $name failed after $max_attempts attempts" | |
| return 1 | |
| } | |
| # Check if ports are available (Bug #4) | |
| check_port() { | |
| local port=$1 | |
| if netstat -tlnp 2>/dev/null | grep -q ":$port"; then | |
| log "β ERROR: Port $port already in use!" | |
| return 1 | |
| fi | |
| return 0 | |
| } | |
| log "Verifying infrastructure ports..." | |
| for port in 7860 7861 7687 20128; do | |
| check_port $port || exit 1 | |
| done | |
| # π Start Services | |
| # Locate memgraph binary (common paths in memgraph-mage) | |
| MEMGRAPH_BIN=$(command -v memgraph || echo "/usr/bin/memgraph") | |
| if [ ! -f "$MEMGRAPH_BIN" ]; then | |
| MEMGRAPH_BIN="/usr/lib/memgraph/memgraph" | |
| fi | |
| start_with_retry "Memgraph" "$MEMGRAPH_BIN --bolt-port 7687" || exit 1 | |
| start_with_retry "ZeroClaw" "zeroclaw gateway" || exit 1 | |
| start_with_retry "OmniRoute" "node /app/scripts/omniroute.js --config /app/config/omniroute-masterfile.json --port 20128" || exit 1 | |
| # Start Graph Viewer on alternate port (7861) | |
| log "Starting Graph Viewer on port 7861..." | |
| GRAPH_VIEWER_PORT=7861 start_with_retry "Graph Viewer" "node /app/scripts/graph-viewer.js" || exit 1 | |
| log "All infrastructure ready! Launching Marimo UI on port 7860..." | |
| # Launch Marimo as the primary UI (port 7860 for HF Spaces healthcheck) | |
| cd /app | |
| nohup marimo run /app/app.py --host 0.0.0.0 --port 7860 --headless > /tmp/marimo.log 2>&1 & | |
| MARIMO_PID=$! | |
| sleep 3 | |
| if ps -p $MARIMO_PID > /dev/null; then | |
| log "β Marimo started (PID: $MARIMO_PID)" | |
| log " Marimo logs: /tmp/marimo.log" | |
| else | |
| log "β ERROR: Marimo failed to start!" | |
| cat /tmp/marimo.log | |
| exit 1 | |
| fi | |
| # Start Pi Agent in background with EOF persistence fix | |
| log "Starting Pi Agent in background..." | |
| cd /app/mom-infra | |
| start_with_retry "Pi Agent" "bash -c 'tail -f /dev/null | npm run pi -- --mode rpc --extensions /app/agent-pi/pi-extensions --skills /app/agent-pi/skills --prompts /app/agent-pi/commands'" || log "Pi Agent finished or failed." | |
| log "All services active!" | |
| log " - Memgraph: port 7687" | |
| log " - ZeroClaw: gateway" | |
| log " - OmniRoute: port 20128" | |
| log " - Graph Viewer: port 7861" | |
| log " - Marimo UI: port 7860 (primary)" | |
| log " - Pi Agent: Background RPC" | |
| # Keep container alive by waiting for all background processes | |
| log "Holding container open. Access the UI at https://your-space.hf.space" | |
| wait | |