VerdantClaw-Final / scripts /entrypoint.sh
TheEdict's picture
Initial deployment to VerdantClaw-Final
09eb9d4 verified
Raw
History Blame Contribute Delete
4.36 kB
#!/bin/bash
# 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