mirror of
https://github.com/garrytan/gstack.git
synced 2026-05-02 03:35:09 +02:00
c86faa7968
* fix: split update check cache TTL + add --force flag UP_TO_DATE cache now expires after 60 min (was 720 min / 12 hours). UPGRADE_AVAILABLE keeps 720 min TTL to keep nagging. --force flag deletes cache before checking, used by /gstack-upgrade standalone invocation to always get a fresh result from GitHub. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: /gstack-upgrade standalone uses --force for fresh check Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: bump version and changelog (v0.4.4) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
165 lines
5.5 KiB
Bash
Executable File
165 lines
5.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# gstack-update-check — periodic version check for all skills.
|
|
#
|
|
# Output (one line, or nothing):
|
|
# JUST_UPGRADED <old> <new> — marker found from recent upgrade
|
|
# UPGRADE_AVAILABLE <old> <new> — remote VERSION differs from local
|
|
# (nothing) — up to date, snoozed, disabled, or check skipped
|
|
#
|
|
# Env overrides (for testing):
|
|
# GSTACK_DIR — override auto-detected gstack root
|
|
# GSTACK_REMOTE_URL — override remote VERSION URL
|
|
# GSTACK_STATE_DIR — override ~/.gstack state directory
|
|
set -euo pipefail
|
|
|
|
GSTACK_DIR="${GSTACK_DIR:-$(cd "$(dirname "$0")/.." && pwd)}"
|
|
STATE_DIR="${GSTACK_STATE_DIR:-$HOME/.gstack}"
|
|
CACHE_FILE="$STATE_DIR/last-update-check"
|
|
MARKER_FILE="$STATE_DIR/just-upgraded-from"
|
|
SNOOZE_FILE="$STATE_DIR/update-snoozed"
|
|
VERSION_FILE="$GSTACK_DIR/VERSION"
|
|
REMOTE_URL="${GSTACK_REMOTE_URL:-https://raw.githubusercontent.com/garrytan/gstack/main/VERSION}"
|
|
|
|
# ─── Force flag (busts cache for standalone /gstack-upgrade) ──
|
|
if [ "${1:-}" = "--force" ]; then
|
|
rm -f "$CACHE_FILE"
|
|
fi
|
|
|
|
# ─── Step 0: Check if updates are disabled ────────────────────
|
|
_UC=$("$GSTACK_DIR/bin/gstack-config" get update_check 2>/dev/null || true)
|
|
if [ "$_UC" = "false" ]; then
|
|
exit 0
|
|
fi
|
|
|
|
# ─── Snooze helper ──────────────────────────────────────────
|
|
# check_snooze <remote_version>
|
|
# Returns 0 if snoozed (should stay quiet), 1 if not snoozed (should output).
|
|
#
|
|
# Snooze file format: <version> <level> <epoch>
|
|
# Level durations: 1=24h, 2=48h, 3+=7d
|
|
# New version (version mismatch) resets snooze.
|
|
check_snooze() {
|
|
local remote_ver="$1"
|
|
if [ ! -f "$SNOOZE_FILE" ]; then
|
|
return 1 # no snooze file → not snoozed
|
|
fi
|
|
local snoozed_ver snoozed_level snoozed_epoch
|
|
snoozed_ver="$(awk '{print $1}' "$SNOOZE_FILE" 2>/dev/null || true)"
|
|
snoozed_level="$(awk '{print $2}' "$SNOOZE_FILE" 2>/dev/null || true)"
|
|
snoozed_epoch="$(awk '{print $3}' "$SNOOZE_FILE" 2>/dev/null || true)"
|
|
|
|
# Validate: all three fields must be non-empty
|
|
if [ -z "$snoozed_ver" ] || [ -z "$snoozed_level" ] || [ -z "$snoozed_epoch" ]; then
|
|
return 1 # corrupt file → not snoozed
|
|
fi
|
|
|
|
# Validate: level and epoch must be integers
|
|
case "$snoozed_level" in *[!0-9]*) return 1 ;; esac
|
|
case "$snoozed_epoch" in *[!0-9]*) return 1 ;; esac
|
|
|
|
# New version dropped? Ignore snooze.
|
|
if [ "$snoozed_ver" != "$remote_ver" ]; then
|
|
return 1
|
|
fi
|
|
|
|
# Compute snooze duration based on level
|
|
local duration
|
|
case "$snoozed_level" in
|
|
1) duration=86400 ;; # 24 hours
|
|
2) duration=172800 ;; # 48 hours
|
|
*) duration=604800 ;; # 7 days (level 3+)
|
|
esac
|
|
|
|
local now
|
|
now="$(date +%s)"
|
|
local expires=$(( snoozed_epoch + duration ))
|
|
if [ "$now" -lt "$expires" ]; then
|
|
return 0 # still snoozed
|
|
fi
|
|
|
|
return 1 # snooze expired
|
|
}
|
|
|
|
# ─── Step 1: Read local version ──────────────────────────────
|
|
LOCAL=""
|
|
if [ -f "$VERSION_FILE" ]; then
|
|
LOCAL="$(cat "$VERSION_FILE" 2>/dev/null | tr -d '[:space:]')"
|
|
fi
|
|
if [ -z "$LOCAL" ]; then
|
|
exit 0 # No VERSION file → skip check
|
|
fi
|
|
|
|
# ─── Step 2: Check "just upgraded" marker ─────────────────────
|
|
if [ -f "$MARKER_FILE" ]; then
|
|
OLD="$(cat "$MARKER_FILE" 2>/dev/null | tr -d '[:space:]')"
|
|
rm -f "$MARKER_FILE"
|
|
rm -f "$SNOOZE_FILE"
|
|
mkdir -p "$STATE_DIR"
|
|
echo "UP_TO_DATE $LOCAL" > "$CACHE_FILE"
|
|
if [ -n "$OLD" ]; then
|
|
echo "JUST_UPGRADED $OLD $LOCAL"
|
|
fi
|
|
exit 0
|
|
fi
|
|
|
|
# ─── Step 3: Check cache freshness ──────────────────────────
|
|
# UP_TO_DATE: 60 min TTL (detect new releases quickly)
|
|
# UPGRADE_AVAILABLE: 720 min TTL (keep nagging)
|
|
if [ -f "$CACHE_FILE" ]; then
|
|
CACHED="$(cat "$CACHE_FILE" 2>/dev/null || true)"
|
|
case "$CACHED" in
|
|
UP_TO_DATE*) CACHE_TTL=60 ;;
|
|
UPGRADE_AVAILABLE*) CACHE_TTL=720 ;;
|
|
*) CACHE_TTL=0 ;; # corrupt → force re-fetch
|
|
esac
|
|
|
|
STALE=$(find "$CACHE_FILE" -mmin +$CACHE_TTL 2>/dev/null || true)
|
|
if [ -z "$STALE" ] && [ "$CACHE_TTL" -gt 0 ]; then
|
|
case "$CACHED" in
|
|
UP_TO_DATE*)
|
|
CACHED_VER="$(echo "$CACHED" | awk '{print $2}')"
|
|
if [ "$CACHED_VER" = "$LOCAL" ]; then
|
|
exit 0
|
|
fi
|
|
;;
|
|
UPGRADE_AVAILABLE*)
|
|
CACHED_OLD="$(echo "$CACHED" | awk '{print $2}')"
|
|
if [ "$CACHED_OLD" = "$LOCAL" ]; then
|
|
CACHED_NEW="$(echo "$CACHED" | awk '{print $3}')"
|
|
if check_snooze "$CACHED_NEW"; then
|
|
exit 0 # snoozed — stay quiet
|
|
fi
|
|
echo "$CACHED"
|
|
exit 0
|
|
fi
|
|
;;
|
|
esac
|
|
fi
|
|
fi
|
|
|
|
# ─── Step 4: Slow path — fetch remote version ────────────────
|
|
mkdir -p "$STATE_DIR"
|
|
|
|
REMOTE=""
|
|
REMOTE="$(curl -sf --max-time 5 "$REMOTE_URL" 2>/dev/null || true)"
|
|
REMOTE="$(echo "$REMOTE" | tr -d '[:space:]')"
|
|
|
|
# Validate: must look like a version number (reject HTML error pages)
|
|
if ! echo "$REMOTE" | grep -qE '^[0-9]+\.[0-9.]+$'; then
|
|
# Invalid or empty response — assume up to date
|
|
echo "UP_TO_DATE $LOCAL" > "$CACHE_FILE"
|
|
exit 0
|
|
fi
|
|
|
|
if [ "$LOCAL" = "$REMOTE" ]; then
|
|
echo "UP_TO_DATE $LOCAL" > "$CACHE_FILE"
|
|
exit 0
|
|
fi
|
|
|
|
# Versions differ — upgrade available
|
|
echo "UPGRADE_AVAILABLE $LOCAL $REMOTE" > "$CACHE_FILE"
|
|
if check_snooze "$REMOTE"; then
|
|
exit 0 # snoozed — stay quiet
|
|
fi
|
|
echo "UPGRADE_AVAILABLE $LOCAL $REMOTE"
|