← back to Professional Directory
scripts/doctor-nightly-v5-check.sh
112 lines
#!/bin/bash
# Doctor v5 nightly run check — runs at 09:00 PT daily, audits last night's mockup gen.
# Wired to com.steve.doctor-nightly-v5-check.
set -uo pipefail
PD="${PD:-/Users/macstudio3/Projects/professional-directory}"
cd "$PD" || exit 1
TODAY=$(date +%Y-%m-%d)
LOG_TXT="$PD/logs/doctor-nightly-v5-check.log"
mkdir -p "$PD/logs"
ts_local() { date +"%H:%M:%S"; }
log() { echo "[v5-check $(ts_local)] $*" | tee -a "$LOG_TXT"; }
# ----- Last nightly run logs -----
NIGHTLY_OUT="$PD/logs/mockups-nightly.out.log"
NIGHTLY_ERR="$PD/logs/mockups-nightly.err.log"
OUT_AGE_MIN=-1
ERR_LINES=0
ERR_TAIL=""
if [ -f "$NIGHTLY_OUT" ]; then
OUT_AGE_MIN=$(( ( $(date +%s) - $(stat -f %m "$NIGHTLY_OUT") ) / 60 ))
fi
if [ -f "$NIGHTLY_ERR" ]; then
ERR_LINES=$(wc -l < "$NIGHTLY_ERR" | tr -d ' ')
ERR_TAIL=$(tail -20 "$NIGHTLY_ERR" 2>/dev/null)
fi
# ----- Mockup files written between 01:00 and 09:00 today -----
MOCK_DIR="$PD/data/mockups"
WROTE_TODAY=$(find "$MOCK_DIR" -maxdepth 1 -name '*.html' -newermt "${TODAY} 01:00" ! -newermt "${TODAY} 09:00" 2>/dev/null | wc -l | tr -d ' ')
TAINTED_TODAY=$(find "$MOCK_DIR" -maxdepth 1 -name '*tainted*' -newermt "${TODAY} 01:00" ! -newermt "${TODAY} 09:00" 2>/dev/null | wc -l | tr -d ' ')
# ----- Run the audit on today's files only -----
AUDIT_REPORT=""
if [ "$WROTE_TODAY" -gt 0 ]; then
AUDIT_REPORT=$(node -e "
const fs = require('fs');
const path = require('path');
const dir = '$MOCK_DIR';
const today = '$TODAY';
const start = Date.parse(today + 'T01:00:00') / 1000;
const end = Date.parse(today + 'T09:00:00') / 1000;
const all = fs.readdirSync(dir).filter(f => f.endsWith('.html'))
.map(f => ({ f, m: fs.statSync(path.join(dir,f)).mtimeMs / 1000 }))
.filter(x => x.m >= start && x.m <= end);
const tainted = all.filter(x => x.f.includes('tainted'));
const clean = all.filter(x => !x.f.includes('tainted'));
console.log(JSON.stringify({ total: all.length, clean: clean.length, tainted: tainted.length, taintRate: all.length ? (tainted.length / all.length * 100).toFixed(1) + '%' : 'n/a' }));
" 2>&1)
fi
# ----- snapshot-mockups.js run? Look for its output marker -----
SNAPSHOT_RAN="unknown"
if [ -f "$NIGHTLY_OUT" ]; then
if grep -q "snapshot-mockups" "$NIGHTLY_OUT" 2>/dev/null || tail -50 "$NIGHTLY_OUT" 2>/dev/null | grep -qi "snapshot"; then
SNAPSHOT_RAN="yes"
else
SNAPSHOT_RAN="not-found-in-log"
fi
fi
# ----- MS1 health right now -----
MS1_STATUS=$(curl -s -o /dev/null -w '%{http_code}' --max-time 5 http://192.168.1.133:11434/api/tags || echo "000")
QWEN_LOADED=$(curl -s --max-time 5 http://192.168.1.133:11434/api/tags 2>/dev/null | python3 -c 'import json,sys; d=json.load(sys.stdin); print("yes" if "qwen3:32b" in [m["name"] for m in d.get("models",[])] else "no")' 2>/dev/null || echo "unknown")
# ----- Body -----
BODY="Doctor v5 nightly check — $TODAY
Run logs:
- mockups-nightly.out.log mtime: $OUT_AGE_MIN min ago
- mockups-nightly.err.log: $ERR_LINES total lines
Files generated 01:00-09:00 today: $WROTE_TODAY
- Tainted: $TAINTED_TODAY
- Audit: ${AUDIT_REPORT:-no files to audit}
snapshot-mockups.js ran: $SNAPSHOT_RAN
MS1 ollama right now: $MS1_STATUS (qwen3:32b loaded: $QWEN_LOADED)
Last 20 lines of err log:
$ERR_TAIL
Auto-generated by com.steve.doctor-nightly-v5-check"
log "files=$WROTE_TODAY tainted=$TAINTED_TODAY out_age=${OUT_AGE_MIN}min err_lines=$ERR_LINES MS1=$MS1_STATUS qwen=$QWEN_LOADED"
# ----- Email Steve via George -----
python3 -c '
import json, urllib.request, sys, os
body = sys.stdin.read()
payload = json.dumps({
"to": "steveabramsdesigns@gmail.com",
"subject": "Doctor v5 nightly check — " + os.environ.get("TODAY", ""),
"body": body
}).encode()
req = urllib.request.Request(
"http://localhost:9850/api/send?account=info",
data=payload,
headers={"Content-Type": "application/json"}
)
try:
r = urllib.request.urlopen(req, timeout=10)
print("george:", r.status)
except Exception as e:
print("george-err:", e, file=sys.stderr)
' TODAY="$TODAY" <<<"$BODY" >> "$LOG_TXT" 2>&1
exit 0