2026-05-30 17:19:52 +00:00
|
|
|
|
#!/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:
|
2026-06-02 10:36:16 +00:00
|
|
|
|
# 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)
|
2026-05-30 17:19:52 +00:00
|
|
|
|
|
|
|
|
|
|
TEMPLATE_DIR="$HOME/.git-templates"
|
2026-06-02 10:36:16 +00:00
|
|
|
|
WITH_UPDATE_HOOK=0
|
|
|
|
|
|
TARGET="."
|
|
|
|
|
|
|
|
|
|
|
|
for arg in "$@"; do
|
|
|
|
|
|
case "$arg" in
|
|
|
|
|
|
--with-update-hook) WITH_UPDATE_HOOK=1 ;;
|
|
|
|
|
|
-*) ;;
|
|
|
|
|
|
*) TARGET="$arg" ;;
|
|
|
|
|
|
esac
|
|
|
|
|
|
done
|
2026-05-30 17:19:52 +00:00
|
|
|
|
|
|
|
|
|
|
if [ ! -d "$TARGET/.git" ]; then
|
|
|
|
|
|
echo "Error: $TARGET is not a git repository" >&2
|
|
|
|
|
|
exit 1
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
echo "Bootstrapping Copilot config in: $TARGET"
|
|
|
|
|
|
|
2026-06-18 10:05:46 +02:00
|
|
|
|
# ── 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
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-30 17:19:52 +00:00
|
|
|
|
# .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"
|
2026-06-18 10:05:46 +02:00
|
|
|
|
_set_dev_shell "$TARGET/.github/copilot-instructions.md"
|
|
|
|
|
|
echo " ✓ .github/copilot-instructions.md created (Default-Shell: $DEV_SHELL; TODO-Felder ausfüllen)"
|
2026-05-30 17:19:52 +00:00
|
|
|
|
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
|
|
|
|
|
|
|
2026-06-10 12:06:35 +02:00
|
|
|
|
# ── 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)"
|
2026-05-30 17:19:52 +00:00
|
|
|
|
fi
|
2026-06-10 12:06:35 +02:00
|
|
|
|
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)"
|
2026-05-30 17:19:52 +00:00
|
|
|
|
else
|
2026-06-10 12:06:35 +02:00
|
|
|
|
echo " ─ docs/history/summary/PROJECT_CONTEXT.md already exists, skipping"
|
2026-05-30 17:19:52 +00:00
|
|
|
|
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
|
|
|
|
|
|
|
2026-06-02 10:36:16 +00:00
|
|
|
|
# ── Git-Hooks – Quality Gate + History ───────────────────────────────────────
|
|
|
|
|
|
mkdir -p "$TARGET/.git/hooks"
|
2026-05-30 17:19:52 +00:00
|
|
|
|
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
|
2026-06-02 10:36:16 +00:00
|
|
|
|
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
|
2026-05-30 17:19:52 +00:00
|
|
|
|
|
2026-05-31 12:51:15 +00:00
|
|
|
|
# ── .gitignore – data/ ausschließen ─────────────────────────────────────────
|
2026-05-30 17:19:52 +00:00
|
|
|
|
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
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-10 10:48:27 +02:00
|
|
|
|
_append_gitignore "data/**/*" "# Persistente Service-Daten (nie committen!)"
|
|
|
|
|
|
_append_gitignore "!data/.gitkeep" ""
|
|
|
|
|
|
_append_gitignore "*:Zone.Identifier" "# Windows Mark-of-the-Web / NTFS ADS cruft"
|
2026-05-30 17:19:52 +00:00
|
|
|
|
|
|
|
|
|
|
if [ "$GITIGNORE_UPDATED" -eq 1 ]; then
|
2026-06-10 10:48:27 +02:00
|
|
|
|
echo " ✓ .gitignore aktualisiert (data/ + Windows-ADS excluded)"
|
2026-05-30 17:19:52 +00:00
|
|
|
|
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"
|
2026-06-10 12:06:35 +02:00
|
|
|
|
echo " - docs/history/summary/PROJECT_CONTEXT.md"
|
2026-05-30 17:19:52 +00:00
|
|
|
|
echo " - docs/USER.md, docs/ADMIN.md, docs/MAINTAINER.md"
|
2026-06-10 12:06:35 +02:00
|
|
|
|
echo " 2. git add .github .vscode docs"
|
2026-05-30 17:19:52 +00:00
|
|
|
|
echo " git commit -m 'chore: add copilot workspace config'"
|
2026-06-02 10:36:16 +00:00
|
|
|
|
echo " 3. Templates aktuell halten: git copilot-update"
|
2026-06-02 11:13:34 +00:00
|
|
|
|
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"
|