114 lines
4.7 KiB
Plaintext
114 lines
4.7 KiB
Plaintext
|
|
#!/usr/bin/env bash
|
||
|
|
# gstack-community-dashboard — community usage stats from Supabase
|
||
|
|
#
|
||
|
|
# Queries the Supabase REST API to show community-wide gstack usage:
|
||
|
|
# skill popularity, crash clusters, version distribution, retention.
|
||
|
|
#
|
||
|
|
# Env overrides (for testing):
|
||
|
|
# GSTACK_DIR — override auto-detected gstack root
|
||
|
|
# GSTACK_SUPABASE_URL — override Supabase project URL
|
||
|
|
# GSTACK_SUPABASE_ANON_KEY — override Supabase anon key
|
||
|
|
set -uo pipefail
|
||
|
|
|
||
|
|
GSTACK_DIR="${GSTACK_DIR:-$(cd "$(dirname "$0")/.." && pwd)}"
|
||
|
|
|
||
|
|
# Source Supabase config if not overridden by env
|
||
|
|
if [ -z "${GSTACK_SUPABASE_URL:-}" ] && [ -f "$GSTACK_DIR/supabase/config.sh" ]; then
|
||
|
|
. "$GSTACK_DIR/supabase/config.sh"
|
||
|
|
fi
|
||
|
|
SUPABASE_URL="${GSTACK_SUPABASE_URL:-}"
|
||
|
|
ANON_KEY="${GSTACK_SUPABASE_ANON_KEY:-}"
|
||
|
|
|
||
|
|
if [ -z "$SUPABASE_URL" ] || [ -z "$ANON_KEY" ]; then
|
||
|
|
echo "gstack community dashboard"
|
||
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||
|
|
echo ""
|
||
|
|
echo "Supabase not configured yet. The community dashboard will be"
|
||
|
|
echo "available once the gstack Supabase project is set up."
|
||
|
|
echo ""
|
||
|
|
echo "For local analytics, run: gstack-analytics"
|
||
|
|
exit 0
|
||
|
|
fi
|
||
|
|
|
||
|
|
# ─── Helper: query Supabase REST API ─────────────────────────
|
||
|
|
query() {
|
||
|
|
local table="$1"
|
||
|
|
local params="${2:-}"
|
||
|
|
curl -sf --max-time 10 \
|
||
|
|
"${SUPABASE_URL}/rest/v1/${table}?${params}" \
|
||
|
|
-H "apikey: ${ANON_KEY}" \
|
||
|
|
-H "Authorization: Bearer ${ANON_KEY}" \
|
||
|
|
2>/dev/null || echo "[]"
|
||
|
|
}
|
||
|
|
|
||
|
|
echo "gstack community dashboard"
|
||
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||
|
|
echo ""
|
||
|
|
|
||
|
|
# ─── Weekly active installs ──────────────────────────────────
|
||
|
|
WEEK_AGO="$(date -u -v-7d +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -u -d '7 days ago' +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || echo "")"
|
||
|
|
if [ -n "$WEEK_AGO" ]; then
|
||
|
|
PULSE="$(curl -sf --max-time 10 \
|
||
|
|
"${SUPABASE_URL}/functions/v1/community-pulse" \
|
||
|
|
-H "Authorization: Bearer ${ANON_KEY}" \
|
||
|
|
2>/dev/null || echo '{"weekly_active":0}')"
|
||
|
|
|
||
|
|
WEEKLY="$(echo "$PULSE" | grep -o '"weekly_active":[0-9]*' | grep -o '[0-9]*' || echo "0")"
|
||
|
|
CHANGE="$(echo "$PULSE" | grep -o '"change_pct":[0-9-]*' | grep -o '[0-9-]*' || echo "0")"
|
||
|
|
|
||
|
|
echo "Weekly active installs: ${WEEKLY}"
|
||
|
|
if [ "$CHANGE" -gt 0 ] 2>/dev/null; then
|
||
|
|
echo " Change: +${CHANGE}%"
|
||
|
|
elif [ "$CHANGE" -lt 0 ] 2>/dev/null; then
|
||
|
|
echo " Change: ${CHANGE}%"
|
||
|
|
fi
|
||
|
|
echo ""
|
||
|
|
fi
|
||
|
|
|
||
|
|
# ─── Skill popularity (top 10) ───────────────────────────────
|
||
|
|
echo "Top skills (last 7 days)"
|
||
|
|
echo "────────────────────────"
|
||
|
|
|
||
|
|
# Query telemetry_events, group by skill
|
||
|
|
EVENTS="$(query "telemetry_events" "select=skill,gstack_version&event_type=eq.skill_run&event_timestamp=gte.${WEEK_AGO}&limit=1000" 2>/dev/null || echo "[]")"
|
||
|
|
|
||
|
|
if [ "$EVENTS" != "[]" ] && [ -n "$EVENTS" ]; then
|
||
|
|
echo "$EVENTS" | grep -o '"skill":"[^"]*"' | awk -F'"' '{print $4}' | sort | uniq -c | sort -rn | head -10 | while read -r COUNT SKILL; do
|
||
|
|
printf " /%-20s %d runs\n" "$SKILL" "$COUNT"
|
||
|
|
done
|
||
|
|
else
|
||
|
|
echo " No data yet"
|
||
|
|
fi
|
||
|
|
echo ""
|
||
|
|
|
||
|
|
# ─── Crash clusters ──────────────────────────────────────────
|
||
|
|
echo "Top crash clusters"
|
||
|
|
echo "──────────────────"
|
||
|
|
|
||
|
|
CRASHES="$(query "crash_clusters" "select=error_class,gstack_version,total_occurrences,identified_users&limit=5" 2>/dev/null || echo "[]")"
|
||
|
|
|
||
|
|
if [ "$CRASHES" != "[]" ] && [ -n "$CRASHES" ]; then
|
||
|
|
echo "$CRASHES" | grep -o '"error_class":"[^"]*"' | awk -F'"' '{print $4}' | head -5 | while read -r ERR; do
|
||
|
|
C="$(echo "$CRASHES" | grep -o "\"error_class\":\"$ERR\"[^}]*\"total_occurrences\":[0-9]*" | grep -o '"total_occurrences":[0-9]*' | head -1 | grep -o '[0-9]*')"
|
||
|
|
printf " %-30s %s occurrences\n" "$ERR" "${C:-?}"
|
||
|
|
done
|
||
|
|
else
|
||
|
|
echo " No crashes reported"
|
||
|
|
fi
|
||
|
|
echo ""
|
||
|
|
|
||
|
|
# ─── Version distribution ────────────────────────────────────
|
||
|
|
echo "Version distribution (last 7 days)"
|
||
|
|
echo "───────────────────────────────────"
|
||
|
|
|
||
|
|
if [ "$EVENTS" != "[]" ] && [ -n "$EVENTS" ]; then
|
||
|
|
echo "$EVENTS" | grep -o '"gstack_version":"[^"]*"' | awk -F'"' '{print $4}' | sort | uniq -c | sort -rn | head -5 | while read -r COUNT VER; do
|
||
|
|
printf " v%-15s %d events\n" "$VER" "$COUNT"
|
||
|
|
done
|
||
|
|
else
|
||
|
|
echo " No data yet"
|
||
|
|
fi
|
||
|
|
|
||
|
|
echo ""
|
||
|
|
echo "For local analytics: gstack-analytics"
|