mirror of
https://github.com/garrytan/gstack.git
synced 2026-05-07 05:56:41 +02:00
fix: wire update_checks into telemetry-sync + session count fallback
Three bug fixes: - Telemetry-sync now pings update_checks on successful event sync (previously only in gstack-update-check on cache-miss path) - community-pulse falls back to distinct session_id count when update_checks is empty - Dashboard queries session_id and shows unique session count Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -70,7 +70,7 @@ echo "Top skills (last 7 days)"
|
|||||||
echo "────────────────────────"
|
echo "────────────────────────"
|
||||||
|
|
||||||
# Query telemetry_events, group by skill
|
# 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 "[]")"
|
EVENTS="$(query "telemetry_events" "select=skill,gstack_version,session_id&event_type=eq.skill_run&event_timestamp=gte.${WEEK_AGO}&limit=1000" 2>/dev/null || echo "[]")"
|
||||||
|
|
||||||
if [ "$EVENTS" != "[]" ] && [ -n "$EVENTS" ]; then
|
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
|
echo "$EVENTS" | grep -o '"skill":"[^"]*"' | awk -F'"' '{print $4}' | sort | uniq -c | sort -rn | head -10 | while read -r COUNT SKILL; do
|
||||||
@@ -109,5 +109,41 @@ else
|
|||||||
echo " No data yet"
|
echo " No data yet"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# ─── Sessions (distinct session_id, works for all tiers) ────
|
||||||
|
echo "Sessions (last 7 days)"
|
||||||
|
echo "──────────────────────"
|
||||||
|
|
||||||
|
if [ "$EVENTS" != "[]" ] && [ -n "$EVENTS" ]; then
|
||||||
|
SESSION_COUNT="$(echo "$EVENTS" | grep -o '"session_id":"[^"]*"' | sort -u | wc -l | tr -d ' ')"
|
||||||
|
echo " ${SESSION_COUNT} unique sessions"
|
||||||
|
else
|
||||||
|
echo " No session data"
|
||||||
|
fi
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
|
# ─── Skill recommendations ─────────────────────────────────
|
||||||
|
# Fetch top skills for recommendations
|
||||||
|
TOP_SKILLS="$(echo "$EVENTS" | grep -o '"skill":"[^"]*"' | awk -F'"' '{print $4}' | sort | uniq -c | sort -rn | head -3 | awk '{print $2}' | tr '\n' ',' | sed 's/,$//')"
|
||||||
|
|
||||||
|
if [ -n "$TOP_SKILLS" ]; then
|
||||||
|
RECS="$(curl -sf --max-time 10 \
|
||||||
|
"${SUPABASE_URL}/functions/v1/community-recommendations?skills=${TOP_SKILLS}" \
|
||||||
|
-H "Authorization: Bearer ${ANON_KEY}" \
|
||||||
|
2>/dev/null || echo '{"recommendations":[]}')"
|
||||||
|
|
||||||
|
REC_LIST="$(echo "$RECS" | grep -o '"skill":"[^"]*"' | awk -F'"' '{print $4}')"
|
||||||
|
REC_REASONS="$(echo "$RECS" | grep -o '"reason":"[^"]*"' | awk -F'"' '{print $4}')"
|
||||||
|
|
||||||
|
if [ -n "$REC_LIST" ]; then
|
||||||
|
echo "Skills you might like"
|
||||||
|
echo "─────────────────────"
|
||||||
|
paste <(echo "$REC_LIST") <(echo "$REC_REASONS") 2>/dev/null | while IFS=$'\t' read -r SKILL REASON; do
|
||||||
|
[ -z "$SKILL" ] && continue
|
||||||
|
printf " /%-20s %s\n" "$SKILL" "${REASON:-}"
|
||||||
|
done
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
echo "For local analytics: gstack-analytics"
|
echo "For local analytics: gstack-analytics"
|
||||||
|
echo "For benchmarks: gstack-community-benchmarks"
|
||||||
|
|||||||
@@ -118,7 +118,26 @@ HTTP_CODE="$(curl -s -o /dev/null -w '%{http_code}' --max-time 10 \
|
|||||||
# ─── Update cursor on success (2xx) ─────────────────────────
|
# ─── Update cursor on success (2xx) ─────────────────────────
|
||||||
case "$HTTP_CODE" in
|
case "$HTTP_CODE" in
|
||||||
2*) NEW_CURSOR=$(( CURSOR + COUNT ))
|
2*) NEW_CURSOR=$(( CURSOR + COUNT ))
|
||||||
echo "$NEW_CURSOR" > "$CURSOR_FILE" 2>/dev/null || true ;;
|
echo "$NEW_CURSOR" > "$CURSOR_FILE" 2>/dev/null || true
|
||||||
|
|
||||||
|
# Ping update_checks (install base proxy)
|
||||||
|
GSTACK_VERSION="$(cat "$GSTACK_DIR/VERSION" 2>/dev/null | tr -d '[:space:]' || echo "unknown")"
|
||||||
|
_OS="$(uname -s | tr '[:upper:]' '[:lower:]')"
|
||||||
|
curl -sf --max-time 5 \
|
||||||
|
-X POST "${ENDPOINT}/update_checks" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-H "apikey: ${ANON_KEY}" \
|
||||||
|
-H "Authorization: Bearer ${ANON_KEY}" \
|
||||||
|
-H "Prefer: return=minimal" \
|
||||||
|
-d "{\"gstack_version\":\"$GSTACK_VERSION\",\"os\":\"$_OS\"}" \
|
||||||
|
>/dev/null 2>&1 || true
|
||||||
|
|
||||||
|
# Trigger community backup if community tier
|
||||||
|
BACKUP_CMD="$GSTACK_DIR/bin/gstack-community-backup"
|
||||||
|
if [ "$TIER" = "community" ] && [ -x "$BACKUP_CMD" ]; then
|
||||||
|
"$BACKUP_CMD" 2>/dev/null &
|
||||||
|
fi
|
||||||
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
# Update rate limit marker
|
# Update rate limit marker
|
||||||
|
|||||||
@@ -15,21 +15,40 @@ Deno.serve(async () => {
|
|||||||
const weekAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString();
|
const weekAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString();
|
||||||
const twoWeeksAgo = new Date(Date.now() - 14 * 24 * 60 * 60 * 1000).toISOString();
|
const twoWeeksAgo = new Date(Date.now() - 14 * 24 * 60 * 60 * 1000).toISOString();
|
||||||
|
|
||||||
// This week's active
|
// This week's active (update_checks)
|
||||||
const { count: thisWeek } = await supabase
|
const { count: thisWeekChecks } = await supabase
|
||||||
.from("update_checks")
|
.from("update_checks")
|
||||||
.select("*", { count: "exact", head: true })
|
.select("*", { count: "exact", head: true })
|
||||||
.gte("checked_at", weekAgo);
|
.gte("checked_at", weekAgo);
|
||||||
|
|
||||||
// Last week's active (for change %)
|
// Last week's active (for change %)
|
||||||
const { count: lastWeek } = await supabase
|
const { count: lastWeekChecks } = await supabase
|
||||||
.from("update_checks")
|
.from("update_checks")
|
||||||
.select("*", { count: "exact", head: true })
|
.select("*", { count: "exact", head: true })
|
||||||
.gte("checked_at", twoWeeksAgo)
|
.gte("checked_at", twoWeeksAgo)
|
||||||
.lt("checked_at", weekAgo);
|
.lt("checked_at", weekAgo);
|
||||||
|
|
||||||
const current = thisWeek ?? 0;
|
let current = thisWeekChecks ?? 0;
|
||||||
const previous = lastWeek ?? 0;
|
let previous = lastWeekChecks ?? 0;
|
||||||
|
|
||||||
|
// Fallback: if update_checks is empty, count distinct sessions from telemetry_events
|
||||||
|
if (current === 0) {
|
||||||
|
const { data: thisWeekSessions } = await supabase
|
||||||
|
.from("telemetry_events")
|
||||||
|
.select("session_id")
|
||||||
|
.eq("event_type", "skill_run")
|
||||||
|
.gte("event_timestamp", weekAgo);
|
||||||
|
|
||||||
|
const { data: lastWeekSessions } = await supabase
|
||||||
|
.from("telemetry_events")
|
||||||
|
.select("session_id")
|
||||||
|
.eq("event_type", "skill_run")
|
||||||
|
.gte("event_timestamp", twoWeeksAgo)
|
||||||
|
.lt("event_timestamp", weekAgo);
|
||||||
|
|
||||||
|
current = new Set((thisWeekSessions ?? []).map((e: { session_id: string }) => e.session_id)).size;
|
||||||
|
previous = new Set((lastWeekSessions ?? []).map((e: { session_id: string }) => e.session_id)).size;
|
||||||
|
}
|
||||||
const changePct = previous > 0
|
const changePct = previous > 0
|
||||||
? Math.round(((current - previous) / previous) * 100)
|
? Math.round(((current - previous) / previous) * 100)
|
||||||
: 0;
|
: 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user