Files
msos/tools/git-hooks/pre-commit
popovskikandClaude Opus 4.8 0d49293693 GEO: FAQPage/NGO/Event schema + autonomous generation for new projects
Generative Engine Optimization pass so AI answer engines (ChatGPT, Gemini,
Perplexity, AI Overviews) can confidently identify and cite MSOS.

Schema (tools/seo_inject.py, propagated to all 231 pages):
- FAQPage JSON-LD parsed from the /faq/ Q&A blocks (33 Q&A x EN/MK/SI)
- Organization upgraded to NGO with entity-disambiguation fields:
  alternateName (all spellings), description, areaServed Slovenia,
  knowsLanguage, and foundingDate 2023-03-05
- Event JSON-LD on all 9 /projects/ recap pages (date + real location)

Autonomous for future content (no code edits to add a project):
- Event/Article dates auto-read from the English page's publish date;
  event city auto-detected from the body (Slovenian-city whitelist).
  ARTICLE_DATES/PROJECT_LOCATIONS are now optional overrides only.
  (Auto-detect corrected Paint & Wine to Nova Gorica.)
- build_listings.py: auto-date fallback so undated new content still lists
- pre-commit hook now runs seo_inject.py --all --sitemap first, then
  listings/botlinks, and re-stages changed pages (idempotent)

Docs: docs/geo-offsite-worklist.md - copy-paste-ready off-site plan
(Wikidata, Wikipedia fixes, directories, Google Business, AI-visibility tests).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-07 22:17:03 +02:00

48 lines
2.3 KiB
Bash
Executable File

#!/bin/sh
# ---------------------------------------------------------------------------
# MSOS pre-commit hook — keeps derived files in sync automatically.
#
# On every commit it regenerates and stages:
# - the technical-SEO <head> block on every page + sitemap.xml/robots.txt
# (tools/seo_inject.py) — canonical, hreflang, meta, and the JSON-LD schema
# (Organization/NGO, Article, Event, FAQPage). Idempotent: unchanged pages
# produce no diff, so it only ever stages pages whose content actually moved.
# - the News hub grid + homepage "Latest news" (tools/build_listings.py)
# - /llms.txt and /links-for-bots/ (tools/build_botlinks.py)
# so adding a blog post or an event/project flows through to its schema, the
# sitemap, News, the homepage and the bot pages without any manual command.
#
# It never blocks a commit: if Python or a generator fails, it warns and lets
# the commit proceed.
#
# Activate once per clone: git config core.hooksPath tools/git-hooks
# ---------------------------------------------------------------------------
set -u
PY="$(command -v python || command -v python3 || true)"
if [ -z "$PY" ]; then
echo "pre-commit: Python not found — skipping News/bot regeneration." >&2
exit 0
fi
# Run from the repo root regardless of where git invoked the hook.
ROOT="$(git rev-parse --show-toplevel 2>/dev/null || echo .)"
cd "$ROOT" || exit 0
# SEO/schema first, so build_listings sees fresh dates and new pages are in the
# sitemap. --all rewrites every page's SEO block idempotently; --sitemap also
# refreshes sitemap.xml + robots.txt.
"$PY" tools/seo_inject.py --all --sitemap >/dev/null 2>&1 \
|| echo "pre-commit: seo_inject.py failed — SEO/schema not refreshed." >&2
"$PY" tools/build_listings.py >/dev/null 2>&1 \
|| echo "pre-commit: build_listings.py failed — News/homepage not refreshed." >&2
"$PY" tools/build_botlinks.py >/dev/null 2>&1 \
|| echo "pre-commit: build_botlinks.py failed — bot pages not refreshed." >&2
# Re-stage generated/derived outputs (no-op when unchanged). `git add -u` only
# touches already-tracked files, so an unrelated commit stages nothing new.
git add -u en mk si >/dev/null 2>&1 || true
git add -- sitemap.xml robots.txt llms.txt links-for-bots >/dev/null 2>&1 || true
exit 0