#!/usr/bin/env bash set -euo pipefail # Hard-fails only when pushing to main: if any file covered by .pre-commit-hooks.yaml # (the external git-hook/CI contract, see ADR-0014) changed since the last tag, # a release must be cut before landing on main, or external consumers pinning # `rev: ` silently miss the change. Pre-commit sets PRE_COMMIT_REMOTE_BRANCH # for pre-push hooks; on every other branch (feature work mid-review) this is a # silent no-op — pushing WIP commits there must not be blocked on cutting a # premature tag (see ADR-0014's repo: local vs pinned self-reference decision). TARGET_BRANCH="refs/heads/main" if [[ "${PRE_COMMIT_REMOTE_BRANCH:-}" != "$TARGET_BRANCH" ]]; then exit 0 fi REPO_ROOT="$(git rev-parse --show-toplevel)" cd "$REPO_ROOT" # Paths whose content .pre-commit-hooks.yaml exposes to external consumers. # Keep in sync with .pre-commit-hooks.yaml's entry: paths. RELEASE_PATHS=( .pre-commit-hooks.yaml scripts/skill-size-check.sh plugins/kyberforge/skills/skill-audit/scripts plugins/kyberforge/skills/skill-audit/assets/vale plugins/kyberforge/skills/agent-audit/scripts plugins/kyberforge/skills/agent-audit/assets/vale ) LAST_TAG="$(git describe --tags --abbrev=0 2>/dev/null || true)" if [[ -z "$LAST_TAG" ]]; then echo "FAIL: no release tag exists yet, but .pre-commit-hooks.yaml already exposes hooks to external consumers." >&2 echo " Fix: cut the first release tag (e.g. v1.0.0) before this lands on main." >&2 exit 1 fi EXISTING_PATHS=() for p in "${RELEASE_PATHS[@]}"; do [[ -e "$p" ]] && EXISTING_PATHS+=("$p") done if [[ ${#EXISTING_PATHS[@]} -eq 0 ]]; then exit 0 fi CHANGED="$(git diff --name-only "$LAST_TAG"..HEAD -- "${EXISTING_PATHS[@]}" 2>/dev/null || true)" if [[ -n "$CHANGED" ]]; then echo "FAIL: files covered by .pre-commit-hooks.yaml changed since $LAST_TAG:" >&2 echo "$CHANGED" | sed 's/^/ /' >&2 echo " Fix: cut a new release tag — external consumers pinning rev: $LAST_TAG would miss this change." >&2 exit 1 fi