From ff84b111259a401a11c9ddea6df0e4cbd2547504 Mon Sep 17 00:00:00 2001 From: Claude Code Date: Thu, 26 Mar 2026 11:38:24 -0700 Subject: [PATCH] =?UTF-8?q?ci(hooks-specific):=20=F0=9F=91=B7=20Add=20vali?= =?UTF-8?q?dation=20checks=20in=20enforce-structure.sh=20hook=20to=20enfor?= =?UTF-8?q?ce=20project=20structure=20rules?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Lilith Autocommit --- .claude/hooks/enforce-structure.sh | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/.claude/hooks/enforce-structure.sh b/.claude/hooks/enforce-structure.sh index 9bffc89c..ea18f16e 100755 --- a/.claude/hooks/enforce-structure.sh +++ b/.claude/hooks/enforce-structure.sh @@ -17,7 +17,7 @@ # │ ├── scenes/ # .tscn + .gd (main, menus, world_map, tests) # │ └── tests/ # GUT unit + integration tests # ├── games/ -# │ └── age-of-four/ +# │ └── age-of-dwarves/ # │ ├── data/ # ALL game JSON (terrain/, units/, spells/, etc.) # │ ├── assets/ # sprites, icons # │ ├── docs/ # game design docs @@ -25,8 +25,8 @@ # │ └── vocabulary.json # engine term -> display string # ├── guide/ # │ ├── engine/ # @magic-civ/guide-engine (shared React components) -# │ ├── age-of-four/ # web app (React + Vite) -# │ └── themes/ -> ../../games/age-of-four # SYMLINK (do not write here) +# │ ├── age-of-dwarves/ # web app (React + Vite) +# │ └── themes/ -> ../../games/age-of-dwarves # SYMLINK (do not write here) # ├── packages/ # │ └── engine-ts/ # @magic-civ/engine-ts (auto-generated from GDScript) # ├── tools/ @@ -42,7 +42,7 @@ # 2. Files must be in allowed top-level directories # 3. No .messy/ paths in runtime code (planning docs exempt) # 4. GDScript files must be <=500 lines -# 5. Game data JSON must live in games/age-of-four/data/ +# 5. Game data JSON must live in games/age-of-dwarves/data/ # 6. guide/themes/ is read-only symlink territory # set -euo pipefail @@ -66,7 +66,7 @@ REL="${FILE#$REPO_ROOT/}" # ── Rule 1: No symlinks ────────────────────────────────────────────────────── # Block creating files inside guide/themes/ (the symlink indirection) if [[ "$REL" == guide/themes/* ]]; then - echo '{"decision":"block","reason":"STRUCTURE VIOLATION: guide/themes/ is a symlink indirection. Write data to games/age-of-four/data/ directly, and guide code to guide/."}' + echo '{"decision":"block","reason":"STRUCTURE VIOLATION: guide/themes/ is a symlink indirection. Write data to games/age-of-dwarves/data/ directly, and guide code to guide/."}' exit 0 fi @@ -112,18 +112,18 @@ if [[ "$REL" == *.gd ]]; then fi fi -# ── Rule 5: Data JSON only in games/age-of-four/data/ ──────────────────────── +# ── Rule 5: Data JSON only in games/age-of-dwarves/data/ ──────────────────────── if [[ "$REL" == *.json ]]; then # Allow package.json, tsconfig.json, vite configs, etc. BASENAME=$(basename "$REL") case "$BASENAME" in package.json|tsconfig.json|tsconfig.*.json|vitest.config.*|.gutconfig.json) ;; *) - # If it's game data (not config), it must be in games/age-of-four/data/ - if [[ "$REL" != games/age-of-four/data/* && "$REL" != games/age-of-four/game.json && "$REL" != games/age-of-four/vocabulary.json && "$REL" != .claude/* && "$REL" != .project/* ]]; then + # If it's game data (not config), it must be in games/age-of-dwarves/data/ + if [[ "$REL" != games/age-of-dwarves/data/* && "$REL" != games/age-of-dwarves/game.json && "$REL" != games/age-of-dwarves/vocabulary.json && "$REL" != .claude/* && "$REL" != .project/* ]]; then # Check if it looks like game data (has "id" field or is in a data-like path) if echo "$CONTENT" | jq -e '.[0].id // .id // .races // .terrain // empty' >/dev/null 2>&1; then - echo "{\"decision\":\"block\",\"reason\":\"STRUCTURE VIOLATION: Game data JSON '$REL' must live in games/age-of-four/data/. The guide reads from there via symlink — never duplicate data.\"}" + echo "{\"decision\":\"block\",\"reason\":\"STRUCTURE VIOLATION: Game data JSON '$REL' must live in games/age-of-dwarves/data/. The guide reads from there via symlink — never duplicate data.\"}" exit 0 fi fi @@ -134,7 +134,15 @@ fi # ── Rule 6: No guide/themes/ directory (symlink violation) ─────────────────── # Already caught by Rule 1, but explicit for clarity if [[ "$REL" == guide/themes/* ]]; then - echo '{"decision":"block","reason":"STRUCTURE VIOLATION: guide/themes/ must not contain files. It should be a symlink to games/age-of-four/. Write data to games/age-of-four/data/ instead."}' + echo '{"decision":"block","reason":"STRUCTURE VIOLATION: guide/themes/ must not contain files. It should be a symlink to games/age-of-dwarves/. Write data to games/age-of-dwarves/data/ instead."}' + exit 0 +fi + +# ── Rule 7: Never edit *.generated.ts files ────────────────────────────────── +# These are auto-generated by the transpiler from GDScript sources. +# Fix the GDScript source + re-run transpiler instead. +if [[ "$REL" == *.generated.ts ]]; then + echo "{\"decision\":\"block\",\"reason\":\"GENERATED FILE: '$REL' is auto-generated by the transpiler. Edit the GDScript source or transpiler assembly instead, then run: uv run tools/transpile-engine/transpile.py\"}" exit 0 fi