大改版,可以针对不同项目引擎进行初始化
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user