2026-03-04 15:56:58 +01:00
|
|
|
#!/usr/bin/env bash
|
|
|
|
|
set -euo pipefail
|
|
|
|
|
|
|
|
|
|
usage() {
|
|
|
|
|
cat <<'USAGE'
|
|
|
|
|
Usage: bin/codex-skills-sync.sh [--check|--apply]
|
|
|
|
|
|
|
|
|
|
Options:
|
|
|
|
|
--check Prüft Drift zwischen Repo-Skills und ~/.codex/skills (Default)
|
|
|
|
|
--apply Synchronisiert Repo-Skills nach ~/.codex/skills
|
|
|
|
|
USAGE
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mode="check"
|
|
|
|
|
if [[ $# -gt 1 ]]; then
|
|
|
|
|
usage
|
|
|
|
|
exit 2
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if [[ $# -eq 1 ]]; then
|
|
|
|
|
case "$1" in
|
|
|
|
|
--check)
|
|
|
|
|
mode="check"
|
|
|
|
|
;;
|
|
|
|
|
--apply)
|
|
|
|
|
mode="apply"
|
|
|
|
|
;;
|
|
|
|
|
-h|--help)
|
|
|
|
|
usage
|
|
|
|
|
exit 0
|
|
|
|
|
;;
|
|
|
|
|
*)
|
|
|
|
|
echo "[ERROR] Unknown option: $1" >&2
|
|
|
|
|
usage
|
|
|
|
|
exit 2
|
|
|
|
|
;;
|
|
|
|
|
esac
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
if ! command -v rsync >/dev/null 2>&1; then
|
|
|
|
|
echo "[ERROR] rsync is required." >&2
|
|
|
|
|
exit 3
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
|
|
|
|
repo_root="$(cd -- "${script_dir}/.." && pwd)"
|
2026-03-19 19:59:08 +01:00
|
|
|
source_dir="${repo_root}/.agents/skills"
|
2026-03-04 15:56:58 +01:00
|
|
|
codex_home_dir="${CODEX_HOME:-${HOME}/.codex}"
|
|
|
|
|
target_dir="${codex_home_dir}/skills"
|
|
|
|
|
managed_skills=(
|
|
|
|
|
"core-guardrails"
|
|
|
|
|
"starterkit-planner"
|
2026-03-09 18:30:52 +01:00
|
|
|
"starterkit-grid-standards"
|
|
|
|
|
"starterkit-php-style-ci"
|
2026-03-04 15:56:58 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
for skill in "${managed_skills[@]}"; do
|
|
|
|
|
if [[ ! -d "${source_dir}/${skill}" ]]; then
|
|
|
|
|
echo "[ERROR] Missing source skill: ${source_dir}/${skill}" >&2
|
|
|
|
|
exit 2
|
|
|
|
|
fi
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
check_skill() {
|
|
|
|
|
local skill="$1"
|
|
|
|
|
local src="${source_dir}/${skill}"
|
|
|
|
|
local dst="${target_dir}/${skill}"
|
|
|
|
|
|
|
|
|
|
if [[ ! -d "${dst}" ]]; then
|
|
|
|
|
echo "[DRIFT] Missing target skill: ${dst}"
|
|
|
|
|
return 1
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
local diff
|
2026-03-09 18:30:52 +01:00
|
|
|
diff="$(diff -qr "${src}" "${dst}" || true)"
|
2026-03-04 15:56:58 +01:00
|
|
|
if [[ -n "${diff}" ]]; then
|
|
|
|
|
echo "[DRIFT] ${skill} differs:"
|
|
|
|
|
echo "${diff}" | sed 's/^/ /'
|
|
|
|
|
return 1
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
echo "[OK] ${skill} is in sync"
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
apply_skill() {
|
|
|
|
|
local skill="$1"
|
|
|
|
|
local src="${source_dir}/${skill}"
|
|
|
|
|
local dst="${target_dir}/${skill}"
|
|
|
|
|
|
|
|
|
|
mkdir -p "${dst}"
|
|
|
|
|
rsync -a --delete "${src}/" "${dst}/"
|
|
|
|
|
echo "[SYNC] ${skill} -> ${dst}"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
status=0
|
|
|
|
|
|
|
|
|
|
if [[ "${mode}" == "apply" ]]; then
|
|
|
|
|
mkdir -p "${target_dir}"
|
|
|
|
|
for skill in "${managed_skills[@]}"; do
|
|
|
|
|
apply_skill "${skill}"
|
|
|
|
|
done
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
for skill in "${managed_skills[@]}"; do
|
|
|
|
|
if ! check_skill "${skill}"; then
|
|
|
|
|
status=1
|
|
|
|
|
fi
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
if [[ ${status} -eq 0 ]]; then
|
|
|
|
|
echo "[OK] codex skill sync check passed"
|
|
|
|
|
else
|
|
|
|
|
echo "[FAIL] codex skill sync check found drift"
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
exit ${status}
|