Files
breakpilot-lehrer/scripts/check-loc.sh
Benjamin Admin 5abdfa202e chore: install refactoring guardrails (Phase 0) [guardrail-change]
- scripts/check-loc.sh: LOC budget checker (500 LOC hard cap)
- .claude/rules/architecture.md: split triggers, patterns per language
- .claude/rules/loc-exceptions.txt: documented escape hatches
- AGENTS.python.md: FastAPI conventions (routes thin, service layer)
- AGENTS.go.md: Go/Gin conventions (handler ≤40 LOC)
- AGENTS.typescript.md: Next.js conventions (page.tsx ≤250 LOC, colocation)
- CLAUDE.md extended with guardrail section + commit markers

273 files currently exceed 500 LOC — to be addressed phase by phase.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-23 12:25:36 +02:00

71 lines
1.8 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
MAX_LOC="${MAX_LOC:-500}"
ROOT_DIR="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
EXCEPTIONS_FILE="${ROOT_DIR}/.claude/rules/loc-exceptions.txt"
red() { printf '\033[31m%s\033[0m\n' "$*"; }
green() { printf '\033[32m%s\033[0m\n' "$*"; }
is_exempt() {
local file="$1"
[[ -f "$EXCEPTIONS_FILE" ]] || return 1
while IFS= read -r line; do
[[ -z "$line" ]] && continue
[[ "$line" =~ ^# ]] && continue
local pattern="${line%%|*}"
pattern="$(echo "$pattern" | xargs)"
if [[ -n "$pattern" ]] && [[ "$file" == $pattern ]]; then
return 0
fi
done < "$EXCEPTIONS_FILE"
return 1
}
count_loc() {
[[ -f "$1" ]] && awk 'END { print NR }' "$1" || echo 0
}
collect_changed_files() {
{ git diff --name-only --cached; git diff --name-only; git ls-files --others --exclude-standard; } | awk 'NF' | sort -u
}
main() {
local mode="changed"
[[ "${1:-}" == "--changed" ]] && mode="changed"
[[ "${1:-}" == "--all" ]] && mode="all"
local files=()
if [[ "$mode" == "changed" ]]; then
IFS=$'\n' read -d '' -r -a files < <(collect_changed_files)
else
IFS=$'\n' read -d '' -r -a files < <(find "$ROOT_DIR" \( -name '*.py' -o -name '*.go' -o -name '*.ts' -o -name '*.tsx' \) -not -path '*/node_modules/*' -not -path '*/.next/*' -not -path '*/__pycache__/*' -not -path '*/venv/*')
fi
local failed=0
local violations=0
for file in "${files[@]}"; do
[[ -f "$file" ]] || continue
is_exempt "$file" && continue
local loc
loc="$(count_loc "$file")"
if (( loc > MAX_LOC )); then
red "VIOLATION: $file ($loc LOC > $MAX_LOC)"
violations=$((violations + 1))
failed=1
fi
done
if (( failed )); then
red ""
red "$violations file(s) exceed ${MAX_LOC} LOC budget."
exit 1
fi
green "LOC budget check passed."
}
main "$@"