#!/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)" source_dir="${repo_root}/tools/codex-skills" codex_home_dir="${CODEX_HOME:-${HOME}/.codex}" target_dir="${codex_home_dir}/skills" managed_skills=( "core-guardrails" "starterkit-planner" "starterkit-grid-standards" "starterkit-php-style-ci" ) 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 diff="$(diff -qr "${src}" "${dst}" || true)" 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}