#!/usr/bin/env bash
# HIGH LVL Clipper โ verification entrypoint. Fails fast. Run before starting any
# feature and before marking one done. Idempotent; safe to re-run. Does NOT start
# servers, deploy, or post anywhere.
set -euo pipefail
cd "$(dirname "$0")"
FF=/opt/homebrew/opt/ffmpeg-full/bin
echo "โโ HIGH LVL Clipper init โโ"
# 1. binaries the render pipeline depends on
[ -x "$FF/ffmpeg" ] || { echo "โ ffmpeg-full missing (brew install ffmpeg-full)"; exit 1; }
[ -x "$FF/ffprobe" ] || { echo "โ ffprobe (ffmpeg-full) missing"; exit 1; }
# capture first: `grep -q` in a pipe + pipefail turns SUCCESS into SIGPIPE failure
FILTERS=$("$FF/ffmpeg" -hide_banner -filters 2>/dev/null)
grep -q " ass " <<<"$FILTERS" || { echo "โ ffmpeg lacks libass (need ffmpeg-full, not slim)"; exit 1; }
command -v node >/dev/null || { echo "โ node missing (need >=22 for engines)"; exit 1; }
NODE_MAJ=$(node -e 'console.log(process.versions.node.split(".")[0])')
[ "$NODE_MAJ" -ge 22 ] || { echo "โ node $NODE_MAJ too old (HyperFrames needs >=22)"; exit 1; }
echo " โ ffmpeg-full (libass) + ffprobe + node $NODE_MAJ"
# 2. python static check โ server + every tool + atomizer must compile
python3 -m py_compile dashboard/server.py dashboard/inspiration.py dashboard/tribe.py \
tools/luxury_render.py tools/motion_render.py tools/hyperframes_render.py \
tools/reframe.py tools/style_render.py tools/quote_cards.py tools/quote_reel_overlay.py \
tools/fonts.py \
atomizer/*.py
echo " โ python compiles clean"
# 3. dashboard inline JS must parse (single-file UI โ a typo kills every tab)
node -e '
const fs=require("fs");
const html=fs.readFileSync("dashboard/index.html","utf8");
const scripts=[...html.matchAll(/<script>([\s\S]*?)<\/script>/g)].map(m=>m[1]).join("\n");
new Function(scripts);' || { echo "โ index.html inline JS has a syntax error"; exit 1; }
echo " โ dashboard JS parses"
# 4. isolated venvs + assets
tools/reframe-venv/bin/python -c "import cv2" 2>/dev/null \
|| { echo "โ reframe-venv broken (uv pip install --python tools/reframe-venv/bin/python 'opencv-python-headless<5' numpy)"; exit 1; }
[ -x tools/video-use/.venv/bin/python ] || echo " โ video-use venv missing (transcription will fail โ see tools/video-use/install.md)"
for lut in cool warm natural; do
[ -f "tools/luts/$lut.cube" ] || { echo "โ missing LUT tools/luts/$lut.cube"; exit 1; }
done
echo " โ venvs + 3 LUTs present"
# 5. iron rule #2 guard: fail if runtime dirs drifted back onto iCloud-managed paths
if grep -q 'Path.home() / "Desktop"' dashboard/server.py; then
echo "โ server.py references ~/Desktop for runtime data (iCloud eviction hazard โ see AGENTS.md rule 2)"; exit 1
fi
echo " โ no iCloud-managed runtime paths"
# 6. health (informational โ never fails the gate)
TOKEN=$(grep -E '^STUDIO_TOKEN=' .env 2>/dev/null | tail -1 | cut -d= -f2- || true)
if [ -n "${TOKEN:-}" ]; then
L=$(curl -s -o /dev/null -w "%{http_code}" --max-time 3 "http://127.0.0.1:5192/api/library?k=$TOKEN" || true)
P=$(curl -s -o /dev/null -w "%{http_code}" --max-time 8 "https://clipper.highlvl.ai/" || true)
# public: the Mini has its OWN token โ a 401 here means edge+tunnel+server are all UP and gating
case "$P" in 200|401) PSTATE="up" ;; *) PSTATE="DOWN($P)" ;; esac
echo " โน local studio: ${L:-down} ยท public link: $PSTATE (start local: HOST=127.0.0.1 PORT=5192 STUDIO_TOKEN=โฆ python3 dashboard/server.py)"
fi
echo ""
echo "Ready. Next steps:"
echo " 1. Read feature_list.json โ pick ONE feature (respect dependencies/blocked)."
echo " 2. Read the top entry of progress.md for Current State."
echo " 3. Deploy to the Mini ONLY via ./ops/deploy-mini.sh (health-gated, auto-rollback)."
echo ""
echo "Definition of done: this gate passes AND the change is exercised for real โ render,"
echo "ffprobe it, extract frames and LOOK at them. Paste command+output as Verification"
echo "Evidence into progress.md, set the feature status. Leave the tree clean."