rd13_copilot_setup/scripts/copilot-update.sh
Conrad Schulz 2b20a985a5 refactor(history): move agent history under docs/history + auto-migration
Konvention geaendert: history/ -> docs/history/ (prompts + summary/PROJECT_CONTEXT.md).
Harter Cutover im pre-commit Hook (Check 4 + Check 6 erwarten docs/history/).
Bestehende Repos werden beim naechsten 'git copilot-update' automatisch per git mv migriert (Fallback mv; bei Konflikt Warnung statt Abbruch).
Angepasst: pre-commit Hook, alle 6 Skripte + selftest, beide copilot-instructions.md, settings.json Session-Protokoll, history.prompt.md, README, USER/ADMIN/MAINTAINER (+ ADMIN Migrationsabschnitt). git-templates/history -> git-templates/docs/history (git mv). Validiert: shellcheck clean, fish -n clean, selftest PASS, Migrationstest PASS (sh+fish+both-present).
2026-06-10 12:06:35 +02:00

271 lines
12 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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
# shellcheck source=/dev/null
. "$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/docs/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/docs/history/summary/PROJECT_CONTEXT.md" "$GIT_TEMPLATE_DIR/docs/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"
# ── 4-pre. Migration: history/ → docs/history/ (einmalig, automatisch) ──────
# Alte Repos haben history/ im Repo-Root. Neuer Standard: docs/history/.
# Wird beim ersten Update automatisch verschoben (git mv, Fallback mv).
if [ -d "$REPO_ROOT/history" ] && [ ! -d "$REPO_ROOT/docs/history" ]; then
echo " → Migriere history/ → docs/history/ ..."
mkdir -p "$REPO_ROOT/docs"
if git -C "$REPO_ROOT" mv history docs/history 2>/dev/null; then
echo " ✓ history/ → docs/history/ verschoben (git mv zum Commit vormerken)"
elif mv "$REPO_ROOT/history" "$REPO_ROOT/docs/history" 2>/dev/null; then
echo " ✓ history/ → docs/history/ verschoben (mv)"
else
echo " ✗ Migration fehlgeschlagen bitte manuell: git mv history docs/history"
fi
elif [ -d "$REPO_ROOT/history" ] && [ -d "$REPO_ROOT/docs/history" ]; then
echo " ⚠ history/ UND docs/history/ vorhanden bitte manuell zusammenführen:"
echo " git mv history/prompts/* docs/history/prompts/ && git rm -r history"
fi
# ── 4a. Git-Hooks aktualisieren ──────────────────────────────────────
HOOKS_DIR="$REPO_ROOT/.git/hooks"
mkdir -p "$HOOKS_DIR"
HOOKS_UPDATED=0
# shellcheck disable=SC2043 # bewusst erweiterbar: weitere Hook-Namen koennen ergaenzt werden
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."