#!/usr/bin/env sh # copilot-update.sh # Zieht die neueste Version des Copilot-Setup-Repos und aktualisiert: # - Dieses Script selbst (~/.local/bin/copilot-update.sh) # - Globale Git-Templates (~/.git-templates/) # - VS Code Prompt-Dateien # - Git-Hooks im aktuellen Repo (pre-commit) # - .github/copilot-instructions.md (Framework-Sektion immer, Projekt-Teil bleibt) # # Usage: # copilot-update.sh # aktuelles Verzeichnis (Git-Repo optional) # git copilot-update # via Git-Alias # ── Konfiguration laden: env > config-file > leer ───────────────────────── # Env-Variablen (Vorrang): # COPILOT_SETUP_REMOTE_SSH / _HTTP Remote-URLs des Setup-Repos # COPILOT_SETUP_DIR lokaler Klon/Arbeitskopie (Offline) # COPILOT_SETUP_CONFIG alternativer Pfad zur Config-Datei # Config-Datei (sh-Syntax, gesourct): $XDG_CONFIG_HOME/copilot-setup/config # Standalone-Skript -> keine gemeinsame Lib sourcebar; gleiche Aufloesung in # deploy.sh. Bei Aenderungen beide Stellen pflegen. _env_ssh="${COPILOT_SETUP_REMOTE_SSH:-}" _env_http="${COPILOT_SETUP_REMOTE_HTTP:-}" _env_dir="${COPILOT_SETUP_DIR:-}" CONFIG_FILE="${COPILOT_SETUP_CONFIG:-${XDG_CONFIG_HOME:-$HOME/.config}/copilot-setup/config}" if [ -f "$CONFIG_FILE" ]; then . "$CONFIG_FILE" fi # Env ueberschreibt Werte aus der Config-Datei [ -n "$_env_ssh" ] && COPILOT_SETUP_REMOTE_SSH="$_env_ssh" [ -n "$_env_http" ] && COPILOT_SETUP_REMOTE_HTTP="$_env_http" [ -n "$_env_dir" ] && COPILOT_SETUP_DIR="$_env_dir" SETUP_REPO_SSH="${COPILOT_SETUP_REMOTE_SSH:-}" SETUP_REPO_HTTP="${COPILOT_SETUP_REMOTE_HTTP:-}" CACHE_DIR="${COPILOT_SETUP_DIR:-$HOME/.copilot-setup}" have_remote() { [ -n "$SETUP_REPO_SSH" ] || [ -n "$SETUP_REPO_HTTP" ]; } clone_setup_repo() { if [ -n "$SETUP_REPO_SSH" ]; then echo " → Klone Setup-Repo (SSH)..." if git clone --quiet "$SETUP_REPO_SSH" "$CACHE_DIR" 2>/dev/null; then echo " ✓ Geklont via SSH"; return 0 fi echo " ✗ SSH fehlgeschlagen" fi if [ -n "$SETUP_REPO_HTTP" ]; then echo " → Klone Setup-Repo (HTTP)..." if git clone --quiet "$SETUP_REPO_HTTP" "$CACHE_DIR" 2>/dev/null; then echo " ✓ Geklont via HTTP"; return 0 fi echo " ✗ HTTP fehlgeschlagen" fi return 1 } # VS Code User-Verzeichnis portabel ueber Editionen/OS ermitteln. # Identischer Block in deploy.sh (Standalone -> keine Lib sourcebar). detect_vscode_user_dir() { for d in \ "$HOME/.vscode-server/data/User" \ "$HOME/.vscode-server-insiders/data/User" \ "$HOME/Library/Application Support/Code/User" \ "$HOME/Library/Application Support/Code - Insiders/User" \ "$HOME/Library/Application Support/VSCodium/User" \ "$HOME/Library/Application Support/Cursor/User" \ "$HOME/.config/Code/User" \ "$HOME/.config/Code - Insiders/User" \ "$HOME/.config/VSCodium/User" \ "$HOME/.config/Cursor/User" \ "$HOME/.var/app/com.visualstudio.code/config/Code/User" \ "/mnt/c/Users/${USER:-}/AppData/Roaming/Code/User" \ "/mnt/c/Users/${USER:-}/AppData/Roaming/Code - Insiders/User" do if [ -d "$d" ]; then printf '%s\n' "$d" return 0 fi done case "$(uname -s)" in Darwin) printf '%s\n' "$HOME/Library/Application Support/Code/User" ;; *) printf '%s\n' "$HOME/.config/Code/User" ;; esac } echo "=== Copilot Update ===" # ── 1. Setup-Repo Cache aktuell halten ─────────────────────────────────────── if [ -d "$CACHE_DIR/.git" ]; then if have_remote; then echo " → Pulling latest from setup repo..." if git -C "$CACHE_DIR" pull --ff-only --quiet 2>/dev/null; then echo " ✓ Cache aktualisiert: $CACHE_DIR" else echo " ⚠ git pull fehlgeschlagen – nutze vorhandenen Cache (offline)" fi else echo " ─ Kein Remote konfiguriert – nutze lokalen Klon: $CACHE_DIR" fi elif [ -d "$CACHE_DIR/git-templates" ]; then echo " ─ Lokale Setup-Quelle ohne .git (Offline-Betrieb): $CACHE_DIR" else if have_remote && clone_setup_repo; then : else echo "" echo " ⚠ Keine Setup-Quelle verfuegbar – Update uebersprungen." if have_remote; then echo " Remote nicht erreichbar:" [ -n "$SETUP_REPO_SSH" ] && echo " SSH: $SETUP_REPO_SSH" [ -n "$SETUP_REPO_HTTP" ] && echo " HTTP: $SETUP_REPO_HTTP" else echo " Kein Remote konfiguriert. Setze COPILOT_SETUP_REMOTE_SSH/_HTTP," echo " COPILOT_SETUP_DIR (lokaler Klon) oder lege $CONFIG_FILE an." fi echo " (Kein Fehler – ohne Quelle gibt es nichts zu aktualisieren.)" exit 0 fi fi SOURCE="$CACHE_DIR" # ── 1b. Self-update: dieses Script selbst aktualisieren ───────────────────── SELF="$HOME/.local/bin/copilot-update.sh" if [ -f "$SOURCE/scripts/copilot-update.sh" ]; then if ! cmp -s "$SOURCE/scripts/copilot-update.sh" "$SELF" 2>/dev/null; then cp "$SOURCE/scripts/copilot-update.sh" "$SELF" chmod +x "$SELF" echo " ✓ copilot-update.sh selbst aktualisiert – starte neue Version..." exec "$SELF" "$@" fi fi GIT_TEMPLATE_DIR="$HOME/.git-templates" # ── 2. ~/.git-templates/ aktualisieren ────────────────────────────────────── mkdir -p "$GIT_TEMPLATE_DIR/.github" "$GIT_TEMPLATE_DIR/.vscode" \ "$GIT_TEMPLATE_DIR/hooks" "$GIT_TEMPLATE_DIR/docs" \ "$GIT_TEMPLATE_DIR/history/summary" cp "$SOURCE/git-templates/.github/copilot-instructions.md" "$GIT_TEMPLATE_DIR/.github/" cp "$SOURCE/git-templates/.vscode/settings.json" "$GIT_TEMPLATE_DIR/.vscode/" cp "$SOURCE/git-templates/.vscode/extensions.json" "$GIT_TEMPLATE_DIR/.vscode/" cp "$SOURCE/git-templates/hooks/pre-commit" "$GIT_TEMPLATE_DIR/hooks/" chmod +x "$GIT_TEMPLATE_DIR/hooks/pre-commit" if [ -f "$SOURCE/git-templates/hooks/post-merge" ]; then cp "$SOURCE/git-templates/hooks/post-merge" "$GIT_TEMPLATE_DIR/hooks/" chmod +x "$GIT_TEMPLATE_DIR/hooks/post-merge" fi cp "$SOURCE/git-templates/docs/USER.md" "$GIT_TEMPLATE_DIR/docs/" cp "$SOURCE/git-templates/docs/ADMIN.md" "$GIT_TEMPLATE_DIR/docs/" cp "$SOURCE/git-templates/docs/MAINTAINER.md" "$GIT_TEMPLATE_DIR/docs/" cp "$SOURCE/git-templates/history/summary/PROJECT_CONTEXT.md" "$GIT_TEMPLATE_DIR/history/summary/" echo " ✓ ~/.git-templates/ aktualisiert" # ── 3. VS Code Prompt-Dateien aktualisieren ─────────────────────────────────── VSCODE_USER="$(detect_vscode_user_dir)" if [ -d "$VSCODE_USER" ]; then mkdir -p "$VSCODE_USER/prompts" PROMPTS_UPDATED=0 for f in "$SOURCE/prompts/"*.prompt.md; do fname="$(basename "$f")" cp "$f" "$VSCODE_USER/prompts/$fname" PROMPTS_UPDATED=$((PROMPTS_UPDATED + 1)) done echo " ✓ $PROMPTS_UPDATED Prompt-Dateien aktualisiert → $VSCODE_USER/prompts/" else echo " ─ VS Code User-Verzeichnis nicht gefunden, Prompts übersprungen" fi # ── 4. Repo-lokale Updates (nur wenn in einem Git-Repo) ────────────────────── REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null) if [ -z "$REPO_ROOT" ]; then echo "" echo " ─ Kein Git-Repo erkannt – repo-lokale Updates übersprungen" echo "" echo "=== Done ===" exit 0 fi echo "" echo " Git-Repo erkannt: $REPO_ROOT" # ── 4a. Git-Hooks aktualisieren ─────────────────────────────────────────────── HOOKS_DIR="$REPO_ROOT/.git/hooks" mkdir -p "$HOOKS_DIR" HOOKS_UPDATED=0 for hook in pre-commit; do if [ -f "$SOURCE/git-templates/hooks/$hook" ]; then cp "$SOURCE/git-templates/hooks/$hook" "$HOOKS_DIR/$hook" chmod +x "$HOOKS_DIR/$hook" HOOKS_UPDATED=$((HOOKS_UPDATED + 1)) echo " ✓ .git/hooks/$hook aktualisiert" fi done if [ "$HOOKS_UPDATED" -eq 0 ]; then echo " ─ Keine Hook-Templates gefunden" fi # ── 4b. copilot-instructions.md: Framework-Sektion immer aktualisieren ───────── # Die Datei besteht aus zwei Teilen: # 1) Framework-Sektion (bis zum ersten ---): Session-Protokoll, Verbotene Aktionen # 2) Projekt-Sektion (ab ---): Stack, Architecture, Conventions (repo-spezifisch) # Der Framework-Teil wird immer aus dem Template aktualisiert. # Der Projekt-Teil bleibt unverändert. COPILOT_INSTRUCTIONS="$REPO_ROOT/.github/copilot-instructions.md" TEMPLATE_INSTRUCTIONS="$SOURCE/git-templates/.github/copilot-instructions.md" if [ -f "$COPILOT_INSTRUCTIONS" ] && [ -f "$TEMPLATE_INSTRUCTIONS" ]; then # Framework-Sektion aus Template (alles vor erstem ---) framework=$(awk '/^---$/{exit} {print}' "$TEMPLATE_INSTRUCTIONS") # Projekt-Sektion aus Ziel-Datei (ab erstem --- inkl.) project=$(awk '/^---$/{found=1} found{print}' "$COPILOT_INSTRUCTIONS") if [ -n "$project" ]; then printf '%s\n\n%s\n' "$framework" "$project" > "$COPILOT_INSTRUCTIONS" echo " ✓ .github/copilot-instructions.md Framework-Sektion aktualisiert" else # Keine Projekt-Sektion vorhanden (noch nicht angepasst) – komplett ersetzen cp "$TEMPLATE_INSTRUCTIONS" "$COPILOT_INSTRUCTIONS" echo " ✓ .github/copilot-instructions.md aktualisiert (noch nicht angepasst)" fi else echo " ─ .github/copilot-instructions.md nicht vorhanden, übersprungen" fi # ── 4c. Fehlende 3-Zielgruppen-Docs anlegen (nur wenn noch nicht vorhanden) ── # Überschreibt nie vorhandene Dateien – nur initial anlegen if [ -d "$REPO_ROOT/docs" ]; then DOCS_CREATED=0 for doc in USER.md ADMIN.md MAINTAINER.md; do if [ ! -f "$REPO_ROOT/docs/$doc" ] && [ -f "$GIT_TEMPLATE_DIR/docs/$doc" ]; then cp "$GIT_TEMPLATE_DIR/docs/$doc" "$REPO_ROOT/docs/$doc" echo " ✓ docs/$doc angelegt (Template)" DOCS_CREATED=$((DOCS_CREATED + 1)) fi done if [ "$DOCS_CREATED" -eq 0 ]; then echo " ─ docs/ 3-Zielgruppen-Docs bereits vorhanden" fi fi echo "" echo "=== Done ===" echo "Tipp: 'git copilot-update' jederzeit ausführen um Templates aktuell zu halten."