dgx-spark-playbooks/nvidia/station-healthcare-agent/assets/scripts/check_sandbox_config.sh
2026-05-26 18:25:53 +00:00

217 lines
8.4 KiB
Bash

#!/usr/bin/env bash
#
# Verify sandbox config matches the repo.
# Catches stale skills, missing files, broken imports, and memory errors.
#
# Usage:
# bash scripts/check_sandbox_config.sh [sandbox-name]
#
# Returns exit code 0 if all checks pass, 1 if any fail.
set -uo pipefail
SANDBOX="${1:-clinical-sandbox}"
REPO_DIR="$(cd "$(dirname "$0")/.." && pwd)"
FAIL=0
WARN=0
green() { printf "\033[32m✓ %s\033[0m\n" "$1"; }
red() { printf "\033[31m✗ %s\033[0m\n" "$1"; FAIL=$((FAIL+1)); }
yellow(){ printf "\033[33m⚠ %s\033[0m\n" "$1"; WARN=$((WARN+1)); }
sandbox_exec() {
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
-o LogLevel=ERROR -o ConnectTimeout=15 \
-o "ProxyCommand=openshell ssh-proxy --gateway-name openshell --name ${SANDBOX}" \
"sandbox@openshell-${SANDBOX}" "$1" 2>/dev/null
}
echo "=== Sandbox Config Check: ${SANDBOX} ==="
echo ""
# ── 1. Sandbox exists and is ready ─────────────────────────────
echo "--- Sandbox Status ---"
PHASE=$(openshell sandbox list 2>/dev/null | grep "$SANDBOX" | awk '{print $NF}' | sed 's/\x1b\[[0-9;]*m//g')
if [ "$PHASE" = "Ready" ]; then
green "Sandbox $SANDBOX is Ready"
else
red "Sandbox $SANDBOX is not Ready (phase: ${PHASE:-not found})"
echo " Run: make setup"
exit 1
fi
# ── 2. Collect all hashes from sandbox in one SSH call ─────────
echo ""
echo "--- Collecting sandbox state (one SSH call) ---"
SANDBOX_STATE=$(sandbox_exec '
echo "=== HASHES ==="
for f in \
~/.openclaw/agents/main/agent/IDENTITY.md \
~/.openclaw/workspace/IDENTITY.md \
~/.openclaw/workspace/skills/fhir-basics/SKILL.md \
~/.openclaw/workspace/skills/analysis-methods/SKILL.md \
~/.openclaw/workspace/skills/clinical-knowledge/SKILL.md \
~/.openclaw/workspace/skills/cohort-compare/SKILL.md \
~/.openclaw/workspace/skills/case-summary/SKILL.md \
~/.openclaw/workspace/skills/clinical-delegation/SKILL.md \
~/.openclaw/workspace/skills/molecular-viz/SKILL.md; do
if [ -f "$f" ]; then
md5sum "$f"
else
echo "MISSING $f"
fi
done
echo "=== HELPERS ==="
if [ -f /sandbox/clinical-intelligence/skills/analysis-methods/scripts/fhir_helpers.py ]; then
echo "HELPERS_EXISTS"
python3 -c "import sys; sys.path.insert(0, \"/sandbox/clinical-intelligence/skills/analysis-methods/scripts\"); from fhir_helpers import fhir_get; print(\"IMPORT_OK\")" 2>&1
else
echo "HELPERS_MISSING"
fi
echo "=== MEMORY ==="
[ -d ~/.openclaw/workspace/memory ] && echo "MEMORY_DIR_EXISTS" || echo "MEMORY_DIR_MISSING"
[ -f ~/.openclaw/workspace/MEMORY.md ] && echo "MEMORY_FILE_EXISTS" || echo "MEMORY_FILE_MISSING"
echo "=== GATEWAY ==="
curl -sf http://127.0.0.1:18789/ >/dev/null 2>&1 && echo "GATEWAY_UP" || echo "GATEWAY_DOWN"
echo "=== AGENTS ==="
openclaw agents list 2>/dev/null | grep -c "^\- " || echo "0"
echo "=== INFERENCE ==="
curl -sf https://inference.local/v1/models 2>/dev/null | python3 -c "import sys,json; d=json.load(sys.stdin); print(d[\"data\"][0][\"id\"])" 2>/dev/null || echo "INFERENCE_FAIL"
echo "=== NESTED ==="
[ -d /sandbox/clinical-intelligence/skills/analysis-methods/analysis-methods ] && echo "NESTED_YES" || echo "NESTED_NO"
')
if [ -z "$SANDBOX_STATE" ]; then
red "Could not connect to sandbox"
exit 1
fi
# ── 3. Parse and check IDENTITY.md ─────────────────────────────
echo ""
echo "--- IDENTITY.md ---"
REPO_ID_HASH=$(md5sum "$REPO_DIR/IDENTITY.md" 2>/dev/null | awk '{print $1}')
AGENT_ID_HASH=$(echo "$SANDBOX_STATE" | grep "agents/main/agent/IDENTITY.md" | awk '{print $1}')
WORKSPACE_ID_HASH=$(echo "$SANDBOX_STATE" | grep "workspace/IDENTITY.md" | head -1 | awk '{print $1}')
if [ "$REPO_ID_HASH" = "$AGENT_ID_HASH" ]; then
green "Agent IDENTITY.md matches repo"
else
red "Agent IDENTITY.md is STALE (repo: ${REPO_ID_HASH:0:8} sandbox: ${AGENT_ID_HASH:0:8})"
fi
if [ "$REPO_ID_HASH" = "$WORKSPACE_ID_HASH" ]; then
green "Workspace IDENTITY.md matches repo"
else
red "Workspace IDENTITY.md is STALE (repo: ${REPO_ID_HASH:0:8} workspace: ${WORKSPACE_ID_HASH:0:8})"
fi
# ── 4. Check each skill ───────────────────────────────────────
echo ""
echo "--- Skills ---"
for skill_dir in "$REPO_DIR"/skills/*/; do
skill_name=$(basename "$skill_dir")
REPO_HASH=$(md5sum "$skill_dir/SKILL.md" 2>/dev/null | awk '{print $1}')
SANDBOX_LINE=$(echo "$SANDBOX_STATE" | grep "workspace/skills/$skill_name/SKILL.md")
if echo "$SANDBOX_LINE" | grep -q "MISSING"; then
red "Skill $skill_name: NOT FOUND in workspace"
else
SANDBOX_HASH=$(echo "$SANDBOX_LINE" | awk '{print $1}')
if [ "$REPO_HASH" = "$SANDBOX_HASH" ]; then
green "Skill $skill_name matches repo"
else
red "Skill $skill_name is STALE (repo: ${REPO_HASH:0:8} workspace: ${SANDBOX_HASH:0:8})"
fi
fi
done
# ── 5. Helpers ─────────────────────────────────────────────────
echo ""
echo "--- Helper Scripts ---"
if echo "$SANDBOX_STATE" | grep -q "HELPERS_EXISTS"; then
green "fhir_helpers.py exists"
else
red "fhir_helpers.py MISSING"
fi
if echo "$SANDBOX_STATE" | grep -q "IMPORT_OK"; then
green "fhir_helpers.py imports OK"
else
red "fhir_helpers.py import FAILED"
fi
# ── 6. Memory ──────────────────────────────────────────────────
echo ""
echo "--- Memory ---"
if echo "$SANDBOX_STATE" | grep -q "MEMORY_DIR_EXISTS"; then
green "memory/ directory exists"
else
red "memory/ directory MISSING (causes ENOENT on session start)"
fi
if echo "$SANDBOX_STATE" | grep -q "MEMORY_FILE_EXISTS"; then
green "MEMORY.md exists"
else
red "MEMORY.md MISSING"
fi
# ── 7. Gateway ─────────────────────────────────────────────────
echo ""
echo "--- OpenClaw Gateway ---"
if echo "$SANDBOX_STATE" | grep -q "GATEWAY_UP"; then
green "OpenClaw gateway responding"
else
red "OpenClaw gateway DOWN"
echo " Fix: make restart"
fi
# ── 8. Agents ──────────────────────────────────────────────────
echo ""
echo "--- Agents ---"
AGENT_COUNT=$(echo "$SANDBOX_STATE" | sed -n '/=== AGENTS ===/,/=== INFERENCE ===/p' | grep -v '===' | head -1 | tr -d '[:space:]')
if [ "${AGENT_COUNT:-0}" -ge 6 ]; then
green "$AGENT_COUNT agents registered"
else
red "Only ${AGENT_COUNT:-0} agents (expected 6)"
fi
# ── 9. Inference ───────────────────────────────────────────────
echo ""
echo "--- Inference ---"
INFERENCE_MODEL=$(echo "$SANDBOX_STATE" | sed -n '/=== INFERENCE ===/,/=== NESTED ===/p' | grep -v '===' | head -1)
if echo "$INFERENCE_MODEL" | grep -q "nemotron"; then
green "Inference: $INFERENCE_MODEL"
else
red "Inference FAILED (got: ${INFERENCE_MODEL:-nothing})"
fi
# ── 10. Port forward ──────────────────────────────────────────
echo ""
echo "--- Port Forward ---"
FWD_STATUS=$(openshell forward list 2>/dev/null | grep "$SANDBOX" | sed 's/\x1b\[[0-9;]*m//g' | grep -o 'running\|dead')
if [ "$FWD_STATUS" = "running" ]; then
green "Port forward 18789 running"
else
red "Port forward 18789 ${FWD_STATUS:-not found}"
fi
# ── 11. Nested directories ────────────────────────────────────
echo ""
echo "--- Directory Structure ---"
if echo "$SANDBOX_STATE" | grep -q "NESTED_YES"; then
red "Nested analysis-methods/analysis-methods/ directory found"
else
green "No nested directory issues"
fi
# ── Summary ────────────────────────────────────────────────────
echo ""
echo "=== Summary ==="
if [ $FAIL -eq 0 ]; then
green "All checks passed ($WARN warning(s))"
exit 0
else
red "$FAIL check(s) FAILED, $WARN warning(s)"
exit 1
fi