rd13_copilot_setup/scripts/copilot-bootstrap.sh
Conrad Schulz 5d0194a7b8
Some checks are pending
CI / Lint & self-test (push) Waiting to run
feat(bootstrap): auto-detect dev shell into copilot-instructions
Neues Default-Shell-Feld in der Projekt-Sektion (nach ---), damit der Agent die richtige Shell-Syntax waehlt. Bootstrap erkennt $SHELL (Fallback fish, Whitelist gegen sed-Injection) und schreibt es in frisch erzeugte copilot-instructions.md; manuell aenderbar und ueberlebt copilot-update. selftest +3 Faelle (sh & fish), beide MAINTAINER.md dokumentiert.
2026-06-18 10:05:46 +02:00

185 lines
7.4 KiB
Bash
Raw Permalink 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-bootstrap.sh
# Fügt Copilot-Grundkonfiguration zu einem bestehenden oder neu erstellten Repo hinzu.
# POSIX-kompatibel: läuft auf bash, dash, sh kein fish nötig.
#
# Usage:
# copilot-bootstrap.sh # aktuelles Verzeichnis
# copilot-bootstrap.sh /path/to/repo # anderes Verzeichnis
# copilot-bootstrap.sh --with-update-hook # + post-merge Hook (auto-update nach git pull)
TEMPLATE_DIR="$HOME/.git-templates"
WITH_UPDATE_HOOK=0
TARGET="."
for arg in "$@"; do
case "$arg" in
--with-update-hook) WITH_UPDATE_HOOK=1 ;;
-*) ;;
*) TARGET="$arg" ;;
esac
done
if [ ! -d "$TARGET/.git" ]; then
echo "Error: $TARGET is not a git repository" >&2
exit 1
fi
echo "Bootstrapping Copilot config in: $TARGET"
# ── Default-Shell des Entwicklungssystems erkennen ───────────────────────────
# Wird in die frisch erzeugte copilot-instructions.md geschrieben, damit der
# Agent die richtige Shell-Syntax fuer Terminal-Kommandos waehlt. Fallback: fish.
if [ -n "${SHELL:-}" ]; then
DEV_SHELL=$(basename "$SHELL")
else
DEV_SHELL=fish
fi
case "$DEV_SHELL" in
''|*[!a-z0-9_-]*) DEV_SHELL=fish ;;
esac
# Ersetzt die `- **Default-Shell:** …`-Zeile in $1 durch den erkannten Wert.
_set_dev_shell() {
f="$1"
[ -f "$f" ] || return 0
grep -q '^- \*\*Default-Shell:\*\*' "$f" 2>/dev/null || return 0
tmp="$f.tmp.$$"
if sed "s|^- \*\*Default-Shell:\*\* .*|- **Default-Shell:** $DEV_SHELL|" "$f" > "$tmp" 2>/dev/null; then
mv "$tmp" "$f"
else
rm -f "$tmp"
fi
}
# .github/copilot-instructions.md
if [ ! -f "$TARGET/.github/copilot-instructions.md" ]; then
mkdir -p "$TARGET/.github"
cp "$TEMPLATE_DIR/.github/copilot-instructions.md" "$TARGET/.github/copilot-instructions.md"
_set_dev_shell "$TARGET/.github/copilot-instructions.md"
echo " ✓ .github/copilot-instructions.md created (Default-Shell: $DEV_SHELL; TODO-Felder ausfüllen)"
else
echo " ─ .github/copilot-instructions.md already exists, skipping"
fi
# .vscode/settings.json
if [ ! -f "$TARGET/.vscode/settings.json" ]; then
mkdir -p "$TARGET/.vscode"
cp "$TEMPLATE_DIR/.vscode/settings.json" "$TARGET/.vscode/settings.json"
echo " ✓ .vscode/settings.json created"
else
echo " ─ .vscode/settings.json already exists, skipping"
fi
# .vscode/extensions.json
if [ ! -f "$TARGET/.vscode/extensions.json" ]; then
mkdir -p "$TARGET/.vscode"
cp "$TEMPLATE_DIR/.vscode/extensions.json" "$TARGET/.vscode/extensions.json"
echo " ✓ .vscode/extensions.json created"
else
echo " ─ .vscode/extensions.json already exists, skipping"
fi
# ── data/ Persistente Service-Daten ────────────────────────────────────────
if [ ! -d "$TARGET/data" ]; then
mkdir -p "$TARGET/data"
touch "$TARGET/data/.gitkeep"
echo " ✓ data/ created (persistente Service-Daten gitignored)"
else
echo " ─ data/ already exists, skipping"
fi
# ── docs/history/ Agent-History und Kontext-Summary ────────────────────────
if [ ! -d "$TARGET/docs/history/prompts" ]; then
mkdir -p "$TARGET/docs/history/prompts"
echo " ✓ docs/history/prompts/ created (Agent-Logs committed)"
fi
if [ ! -f "$TARGET/docs/history/summary/PROJECT_CONTEXT.md" ]; then
mkdir -p "$TARGET/docs/history/summary"
cp "$TEMPLATE_DIR/docs/history/summary/PROJECT_CONTEXT.md" "$TARGET/docs/history/summary/PROJECT_CONTEXT.md"
echo " ✓ docs/history/summary/PROJECT_CONTEXT.md created (Agent-Kontext committed)"
else
echo " ─ docs/history/summary/PROJECT_CONTEXT.md already exists, skipping"
fi
# ── docs/ Zielgruppen-Dokumentation ────────────────────────────────────────
if [ ! -d "$TARGET/docs" ]; then
mkdir -p "$TARGET/docs"
cp "$TEMPLATE_DIR/docs/USER.md" "$TARGET/docs/USER.md"
cp "$TEMPLATE_DIR/docs/ADMIN.md" "$TARGET/docs/ADMIN.md"
cp "$TEMPLATE_DIR/docs/MAINTAINER.md" "$TARGET/docs/MAINTAINER.md"
echo " ✓ docs/ created with USER.md, ADMIN.md, MAINTAINER.md (TODO-Felder ausfüllen)"
else
# Fehlende Zielgruppen-Docs ergänzen ohne vorhandene zu überschreiben
for doc in USER ADMIN MAINTAINER; do
if [ ! -f "$TARGET/docs/${doc}.md" ]; then
cp "$TEMPLATE_DIR/docs/${doc}.md" "$TARGET/docs/${doc}.md"
echo " ✓ docs/${doc}.md created"
else
echo " ─ docs/${doc}.md already exists, skipping"
fi
done
fi
# ── Git-Hooks Quality Gate + History ───────────────────────────────────────
mkdir -p "$TARGET/.git/hooks"
if [ ! -f "$TARGET/.git/hooks/pre-commit" ]; then
cp "$TEMPLATE_DIR/hooks/pre-commit" "$TARGET/.git/hooks/pre-commit"
chmod +x "$TARGET/.git/hooks/pre-commit"
echo " ✓ .git/hooks/pre-commit installed (Quality Gate: Tests + Docs)"
else
echo " ─ .git/hooks/pre-commit already exists, skipping"
fi
if [ ! -f "$TARGET/.git/hooks/post-commit" ] && [ -f "$TEMPLATE_DIR/hooks/post-commit" ]; then
cp "$TEMPLATE_DIR/hooks/post-commit" "$TARGET/.git/hooks/post-commit"
chmod +x "$TARGET/.git/hooks/post-commit"
echo " ✓ .git/hooks/post-commit installed (Auto-History-Log)"
fi
# ── post-merge Hook opt-in: automatisches copilot-update nach git pull ──────
if [ "$WITH_UPDATE_HOOK" -eq 1 ]; then
if [ -f "$TEMPLATE_DIR/hooks/post-merge" ]; then
if [ ! -f "$TARGET/.git/hooks/post-merge" ]; then
cp "$TEMPLATE_DIR/hooks/post-merge" "$TARGET/.git/hooks/post-merge"
chmod +x "$TARGET/.git/hooks/post-merge"
echo " ✓ .git/hooks/post-merge installed (Copilot-Update nach git pull)"
else
echo " ─ .git/hooks/post-merge already exists, skipping"
fi
fi
fi
# ── .gitignore data/ ausschließen ─────────────────────────────────────────
GITIGNORE="$TARGET/.gitignore"
GITIGNORE_UPDATED=0
_append_gitignore() {
if ! grep -qF "$1" "$GITIGNORE" 2>/dev/null; then
printf '\n%s\n%s\n' "$2" "$1" >> "$GITIGNORE"
GITIGNORE_UPDATED=1
fi
}
_append_gitignore "data/**/*" "# Persistente Service-Daten (nie committen!)"
_append_gitignore "!data/.gitkeep" ""
_append_gitignore "*:Zone.Identifier" "# Windows Mark-of-the-Web / NTFS ADS cruft"
if [ "$GITIGNORE_UPDATED" -eq 1 ]; then
echo " ✓ .gitignore aktualisiert (data/ + Windows-ADS excluded)"
else
echo " ─ .gitignore already has required entries, skipping"
fi
echo ""
echo "Done. Nächste Schritte:"
echo " 1. TODO-Felder ausfüllen:"
echo " - .github/copilot-instructions.md"
echo " - docs/history/summary/PROJECT_CONTEXT.md"
echo " - docs/USER.md, docs/ADMIN.md, docs/MAINTAINER.md"
echo " 2. git add .github .vscode docs"
echo " git commit -m 'chore: add copilot workspace config'"
echo " 3. Templates aktuell halten: git copilot-update"
echo ""
echo " Hinweis: Git-Hooks (pre-commit, post-commit) werden NICHT automatisch"
echo " aktualisiert wenn sie bereits existieren. Neue Hook-Versionen holen mit:"
echo " git copilot-update"