Gunnar

nordisk/holger

.githooks/pre-commit

#!/bin/sh
# Pre-commit hook for holger.
#
#   1. nornir — re-render managed markdown (README.md / CHANGELOG.md) and stage it.
#   2. kvasir — regenerate the tracked AI-context packs
#      (docs/ai-context.md + docs/ai-context-full.md) from .nornir/ai-context.toml
#      and the code, and stage them, so they never drift.
#
# Rules:
#   * Markdown only — never regenerates the depgraph SVG or the rendered book.
#   * A MISSING tool never blocks a commit (warn + skip).
#   * kvasir DOES block the commit if the metadata is broken (blocking validation
#     errors) — that is a real defect to fix, not a doc refresh.
set -u

REPO='holger'
REPO_ROOT="$(git rev-parse --show-toplevel)"

# ── 1. nornir: managed markdown (README.md / CHANGELOG.md) ────────────────────
if command -v nornir >/dev/null 2>&1; then
    if out=$(nornir docs render "$REPO" 2>&1); then
        # HARD RULE: markdown only — discard any regenerated assets.
        # Also discard .nornir/README-full.md: the installed nornir blanks its
        # benchmark tables ("no bench history yet") whenever the bench warehouse
        # is unreachable, which would clobber the committed numbers. Restore it so
        # only README.md / CHANGELOG.md are refreshed here; regenerate README-full
        # deliberately (with the warehouse available) when the benches change.
        for restore in .nornir/assets/depgraph.svg docs/book.pdf .nornir/README-full.md; do
            [ -f "$restore" ] && git checkout -- "$restore" 2>/dev/null || true
        done
        for f in README.md CHANGELOG.md; do
            [ -f "$f" ] && git add -- "$f" 2>/dev/null || true
        done
    else
        echo "nornir: docs render failed — committing without README/CHANGELOG refresh" >&2
        echo "$out" | sed 's/^/nornir: /' >&2
    fi
else
    echo "nornir: README/CHANGELOG render skipped (nornir not on PATH)" >&2
fi

# ── 2. kvasir: AI-context packs (docs/ai-context{,-full}.md) ──────────────────
# Only regenerate when this commit actually stages code / a manifest / the
# maintained metadata — a doc-only or config-only commit cannot change the packs'
# content, so skip it (avoids churning the 490 KB full pack and re-stamping the
# snapshot on every commit).
if git diff --cached --name-only | grep -qE '\.rs$|(^|/)Cargo\.toml$|^\.nornir/ai-context\.toml$'; then
    kvasir_relevant=1
else
    kvasir_relevant=0
fi

# Prefer kvasir on PATH; else fall back to a sibling release build.
KVASIR="$(command -v kvasir 2>/dev/null || true)"
if [ -z "$KVASIR" ] && [ -x "$REPO_ROOT/../kvasir/target/release/kvasir" ]; then
    KVASIR="$REPO_ROOT/../kvasir/target/release/kvasir"
fi

if [ "$kvasir_relevant" = 0 ]; then
    : # no code/metadata staged — packs cannot have changed; leave them as-is.
elif [ -n "$KVASIR" ]; then
    log="$(mktemp)"
    if "$KVASIR" "$REPO_ROOT" >"$log" 2>&1; then
        git add -- docs/ai-context.md docs/ai-context-full.md 2>/dev/null || true
    else
        echo "kvasir: AI-context generation has BLOCKING validation errors — commit aborted." >&2
        echo "kvasir: fix .nornir/ai-context.toml (or run: kvasir .) and retry." >&2
        sed 's/^/kvasir: /' "$log" >&2
        rm -f "$log"
        exit 1
    fi
    rm -f "$log"
else
    echo "kvasir: AI-context refresh skipped (kvasir not found on PATH or at ../kvasir/target/release)" >&2
    echo "kvasir: install with 'cargo install --path ../kvasir' to keep docs/ai-context*.md in sync." >&2
fi

exit 0