大改版,可以针对不同项目引擎进行初始化

This commit is contained in:
Nostars Developer
2026-07-27 15:09:13 +08:00
parent 6446261c69
commit 62efb3778c
112 changed files with 11020 additions and 899 deletions

View File

@@ -1,5 +1,5 @@
#!/usr/bin/env bash
# Changelog sync guard比较 Godot 源码/配置与本会话起点、changelog 的 mtime
# Changelog sync guard按活动扫描配置提示本会话内尚未提交的项目改动
emit_empty() {
printf '{}\n'
@@ -18,8 +18,14 @@ repo_root=$(dirname -- "$cursor_dir")
changelog="$cursor_dir/changelog/changelog-headlines.md"
ack_file="$cursor_dir/changelog/.changelog-ack"
session_marker="$cursor_dir/changelog/.session-start"
scan_config="$script_dir/changelog-scan.json"
if [ ! -f "$changelog" ]; then
if [ ! -f "$changelog" ] || [ ! -f "$scan_config" ]; then
emit_empty
exit 0
fi
if [ ! -f "$session_marker" ]; then
emit_empty
exit 0
fi
@@ -38,66 +44,6 @@ if [ -f "$ack_file" ]; then
fi
fi
comparison_file=$changelog
if [ -f "$session_marker" ]; then
changelog_mtime=$(get_mtime "$changelog")
session_mtime=$(get_mtime "$session_marker")
if [ -n "$changelog_mtime" ] && [ -n "$session_mtime" ] &&
[ "$session_mtime" -gt "$changelog_mtime" ] 2>/dev/null; then
comparison_file=$session_marker
fi
fi
newer_file=''
while IFS= read -r candidate; do
newer_file=$candidate
break
done < <(
find "$repo_root" \
\( -type d \( \
-name '.git' -o \
-name '.cursor' -o \
-name '.godot' -o \
-name 'node_modules' -o \
-name '__pycache__' -o \
-name 'venv' -o \
-name '.venv' -o \
-name 'dist' -o \
-name 'build' -o \
-name 'out' -o \
-name 'bin' -o \
-name 'obj' -o \
-name 'export' -o \
-name 'exports' -o \
-name 'coverage' -o \
-name 'tmp' -o \
-name 'temp' \
\) -prune \) -o \
\( -type f \( \
-iname 'project.godot' -o \
-iname '*.gd' -o \
-iname '*.tscn' -o \
-iname '*.tres' -o \
-iname '*.res' -o \
-iname '*.gdshader' -o \
-iname '*.cfg' -o \
-iname '*.json' -o \
-iname '*.cs' -o \
-iname '*.csproj' -o \
-iname '*.py' -o \
-iname '*.ps1' -o \
-iname '*.sh' \
\) -newer "$comparison_file" -print \) 2>/dev/null
)
if [ -z "$newer_file" ]; then
emit_empty
exit 0
fi
relative_file=${newer_file#"$repo_root"/}
message="[Hook] Godot source/config is newer than the changelog (e.g. $relative_file). Run dev-changelog Skill operation A now: add a fragment under .cursor/changelog/entries/ and rebuild the changelog views."
python_cmd=''
for candidate in python3 python; do
if command -v "$candidate" >/dev/null 2>&1 &&
@@ -107,24 +53,111 @@ for candidate in python3 python; do
fi
done
if [ -n "$python_cmd" ]; then
result=$(
printf '%s' "$message" | "$python_cmd" -c '
if [ -z "$python_cmd" ]; then
emit_empty
exit 0
fi
result=$(
"$python_cmd" - "$repo_root" "$changelog" "$session_marker" "$scan_config" <<'PY'
import json
import os
from pathlib import Path
import subprocess
import sys
print(json.dumps(
{"followup_message": sys.stdin.read()},
ensure_ascii=False,
separators=(",", ":"),
))
' 2>/dev/null
) || result='{}'
if [ -n "$result" ]; then
printf '%s\n' "$result"
else
emit_empty
fi
repo_root = Path(sys.argv[1]).resolve()
changelog = Path(sys.argv[2])
session_marker = Path(sys.argv[3])
scan_config = Path(sys.argv[4])
def emit(value):
print(json.dumps(value, ensure_ascii=False, separators=(",", ":")))
try:
config = json.loads(scan_config.read_text(encoding="utf-8"))
if config.get("schema_version") != 1:
raise ValueError("unsupported schema")
names = {
value.casefold()
for value in config.get("included_names", [])
if isinstance(value, str) and value
}
extensions = {
value.casefold()
for value in config.get("included_extensions", [])
if isinstance(value, str) and value
}
excluded = {
value.casefold()
for value in config.get("excluded_directories", [])
if isinstance(value, str) and value
}
if not names and not extensions:
emit({})
raise SystemExit(0)
status = subprocess.run(
["git", "-C", str(repo_root), "status", "--porcelain=v1",
"--untracked-files=all", "--"],
check=False,
capture_output=True,
text=True,
encoding="utf-8",
)
if status.returncode != 0 or not status.stdout.strip():
emit({})
raise SystemExit(0)
comparison_mtime = max(
changelog.stat().st_mtime,
session_marker.stat().st_mtime,
)
for current_root, directory_names, file_names in os.walk(repo_root):
directory_names[:] = [
name for name in directory_names if name.casefold() not in excluded
]
current = Path(current_root)
for file_name in file_names:
candidate = current / file_name
if (
file_name.casefold() not in names
and candidate.suffix.casefold() not in extensions
):
continue
try:
if candidate.stat().st_mtime <= comparison_mtime:
continue
except OSError:
continue
relative = candidate.relative_to(repo_root).as_posix()
path_status = subprocess.run(
["git", "-C", str(repo_root), "status", "--porcelain=v1",
"--untracked-files=all", "--", relative],
check=False,
capture_output=True,
text=True,
encoding="utf-8",
)
if path_status.returncode == 0 and path_status.stdout.strip():
message = (
"[Hook] Project source/config has an uncommitted change newer "
f"than this session and the changelog (e.g. {relative}). "
"Run dev-changelog Skill operation A now: add a fragment under "
".cursor/changelog/entries/ and rebuild the changelog views."
)
emit({"followup_message": message})
raise SystemExit(0)
emit({})
except SystemExit:
raise
except Exception:
emit({})
PY
) || result='{}'
if [ -n "$result" ]; then
printf '%s\n' "$result"
else
emit_empty
fi