Lucy kann Projekt-Repos anlegen (gitea-repo-create.sh) - PRIVAT-only
Lucke im "Projekte selbst starten"-Weg: Werkstatt konnte nur Branches in bestehende Repos proposen, kein neues Projekt-Repo anlegen. Neues Skript: POST /api/v1/user/repos, IMMER privat (Gitea ist oeffentlich erreichbar!), auto_init + default main, Token aus ~/.git-credentials (nie ausgegeben), Audit-Log + stiller Chronik-Spiegel je Anlage. Braucht Token-Scope write:user (aktuelles Box-Token hat nur write:repository); ohne das meldet das Skript GENAU, welches Token in Gitea zu generieren ist, statt kryptisch zu scheitern. Token-Upgrade = Commander-Handgriff (Credential). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+4
-1
@@ -126,6 +126,9 @@ cp "$SRC/deploy/pruefstand/pruefstand.sh" "$HOME/.hermes/scripts/pruefstand.sh"
|
|||||||
# Python-Nebendienst-venvs (mem0, voice) — melden nur, ändern nichts.
|
# Python-Nebendienst-venvs (mem0, voice) — melden nur, ändern nichts.
|
||||||
cp "$SRC/deploy/restore-probe.sh" "$HOME/.hermes/scripts/restore-probe.sh"
|
cp "$SRC/deploy/restore-probe.sh" "$HOME/.hermes/scripts/restore-probe.sh"
|
||||||
cp "$SRC/deploy/venv-audit.sh" "$HOME/.hermes/scripts/venv-audit.sh"
|
cp "$SRC/deploy/venv-audit.sh" "$HOME/.hermes/scripts/venv-audit.sh"
|
||||||
|
# Gitea-Repo-Anlage (17.07.2026): schließt Lucys „Projekte selbst starten"-Lücke —
|
||||||
|
# legt PRIVATE Projekt-Repos an (Token aus ~/.git-credentials, braucht write:user-Scope).
|
||||||
|
cp "$SRC/deploy/gitea-repo-create.sh" "$HOME/.hermes/scripts/gitea-repo-create.sh"
|
||||||
# Werkstatt-Kanban-Profil (Ideen-Queue, 10.07.2026): Leitplanken des Worker-Profils nachziehen
|
# Werkstatt-Kanban-Profil (Ideen-Queue, 10.07.2026): Leitplanken des Worker-Profils nachziehen
|
||||||
# (Profil selbst wurde einmalig per `hermes profile create werkstatt --clone` angelegt).
|
# (Profil selbst wurde einmalig per `hermes profile create werkstatt --clone` angelegt).
|
||||||
[ -d "$HOME/.hermes/profiles/werkstatt" ] && cp "$SRC/deploy/werkstatt-SOUL.md" "$HOME/.hermes/profiles/werkstatt/SOUL.md"
|
[ -d "$HOME/.hermes/profiles/werkstatt" ] && cp "$SRC/deploy/werkstatt-SOUL.md" "$HOME/.hermes/profiles/werkstatt/SOUL.md"
|
||||||
@@ -133,7 +136,7 @@ cp "$SRC/deploy/venv-audit.sh" "$HOME/.hermes/scripts/venv-audit.sh"
|
|||||||
# statt Lucy-default. Profil selbst wird einmalig per `hermes profile create betrieb
|
# statt Lucy-default. Profil selbst wird einmalig per `hermes profile create betrieb
|
||||||
# --clone-from werkstatt` angelegt (model coder→hermes, Description fürs Specifier-Routing).
|
# --clone-from werkstatt` angelegt (model coder→hermes, Description fürs Specifier-Routing).
|
||||||
[ -d "$HOME/.hermes/profiles/betrieb" ] && cp "$SRC/deploy/betrieb-SOUL.md" "$HOME/.hermes/profiles/betrieb/SOUL.md"
|
[ -d "$HOME/.hermes/profiles/betrieb" ] && cp "$SRC/deploy/betrieb-SOUL.md" "$HOME/.hermes/profiles/betrieb/SOUL.md"
|
||||||
chmod +x "$HOME/.hermes/scripts/fremdblick.sh" "$HOME/.hermes/scripts/dreaming-feed.sh" "$HOME/.hermes/scripts/worker.sh" "$HOME/.hermes/scripts/chef-gutachter-feed.sh" "$HOME/.hermes/scripts/hermes-release-radar-feed.sh" "$HOME/.hermes/scripts/radar-selbstkritik-wrapper.sh" "$HOME/.hermes/scripts/idle-radar-feed.sh" "$HOME/.hermes/scripts/selbst-inventur.sh" "$HOME/.hermes/scripts/karten-gutachter.sh" "$HOME/.hermes/scripts/trend-radar-feed.sh" "$HOME/.hermes/scripts/pruefstand.sh" "$HOME/.hermes/scripts/restore-probe.sh" "$HOME/.hermes/scripts/venv-audit.sh"
|
chmod +x "$HOME/.hermes/scripts/fremdblick.sh" "$HOME/.hermes/scripts/dreaming-feed.sh" "$HOME/.hermes/scripts/worker.sh" "$HOME/.hermes/scripts/chef-gutachter-feed.sh" "$HOME/.hermes/scripts/hermes-release-radar-feed.sh" "$HOME/.hermes/scripts/radar-selbstkritik-wrapper.sh" "$HOME/.hermes/scripts/idle-radar-feed.sh" "$HOME/.hermes/scripts/selbst-inventur.sh" "$HOME/.hermes/scripts/karten-gutachter.sh" "$HOME/.hermes/scripts/trend-radar-feed.sh" "$HOME/.hermes/scripts/pruefstand.sh" "$HOME/.hermes/scripts/restore-probe.sh" "$HOME/.hermes/scripts/venv-audit.sh" "$HOME/.hermes/scripts/gitea-repo-create.sh"
|
||||||
# Werkstatt-Skill (Autonomie E6): Selbstwartungs-Kreislauf für Hermes.
|
# Werkstatt-Skill (Autonomie E6): Selbstwartungs-Kreislauf für Hermes.
|
||||||
mkdir -p "$HOME/.hermes/skills/wartung"
|
mkdir -p "$HOME/.hermes/skills/wartung"
|
||||||
cp "$SRC/deploy/skills/wartung/SKILL.md" "$HOME/.hermes/skills/wartung/SKILL.md"
|
cp "$SRC/deploy/skills/wartung/SKILL.md" "$HOME/.hermes/skills/wartung/SKILL.md"
|
||||||
|
|||||||
@@ -0,0 +1,84 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Gitea-Repo-Anlage für Lucy (17.07.2026): schließt die Lücke im „Projekte selbst
|
||||||
|
# starten"-Weg — bislang konnte die Werkstatt nur Branches in BESTEHENDE Repos
|
||||||
|
# proposen, aber kein neues Projekt-Repo anlegen.
|
||||||
|
#
|
||||||
|
# Nutzung: gitea-repo-create.sh <name> ["Beschreibung"]
|
||||||
|
# Ergebnis (stdout, letzte Zeile): CLONE <https-clone-url> → Aufrufer kann direkt klonen.
|
||||||
|
#
|
||||||
|
# HARTE Sicherheits-Leitplanken (Gitea ist öffentlich erreichbar!):
|
||||||
|
# • Repos werden IMMER PRIVAT angelegt (kein öffentliches Repo aus Versehen).
|
||||||
|
# • Token wird aus ~/.git-credentials gelesen, NIE ausgegeben/geloggt.
|
||||||
|
# • Jede Anlage wird protokolliert (Audit-Spur) + still an die Chronik gespiegelt.
|
||||||
|
# Braucht ein Token mit Scope `write:user` (zusätzlich zu `write:repository`); ohne das
|
||||||
|
# meldet Gitea 403 — das Skript sagt dann genau, was zu tun ist (Token in Gitea neu
|
||||||
|
# generieren), statt kryptisch zu scheitern.
|
||||||
|
set -uo pipefail
|
||||||
|
|
||||||
|
NAME="${1:-}"
|
||||||
|
BESCHREIBUNG="${2:-Von Lucy angelegtes Projekt-Repo.}"
|
||||||
|
CRED="$HOME/.git-credentials"
|
||||||
|
LOG="$HOME/.hermes/state/gitea-repos-created.log"
|
||||||
|
|
||||||
|
if [ -z "$NAME" ]; then
|
||||||
|
echo "Nutzung: gitea-repo-create.sh <name> [\"Beschreibung\"]" >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
# Repo-Name defensiv prüfen (Gitea erlaubt Buchstaben/Ziffern/-/_/.)
|
||||||
|
if ! printf '%s' "$NAME" | grep -qE '^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$'; then
|
||||||
|
echo "Ungültiger Repo-Name '$NAME' (erlaubt: Buchstaben/Ziffern/.-_, Beginn alphanumerisch)." >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
if [ ! -r "$CRED" ]; then
|
||||||
|
echo "Keine ~/.git-credentials gefunden — ohne gespeicherte Gitea-Anmeldung geht das nicht." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Zeile für den Gitea-Host herausgreifen (falls mehrere Hosts hinterlegt sind)
|
||||||
|
LINE="$(grep -m1 'git\.tobisniceshomelab\.ddnsfree\.com' "$CRED" || head -1 "$CRED")"
|
||||||
|
USER="$(printf '%s' "$LINE" | sed -E 's#https://([^:]+):.*#\1#')"
|
||||||
|
TOKEN="$(printf '%s' "$LINE" | sed -E 's#https://[^:]+:([^@]+)@.*#\1#')"
|
||||||
|
HOST="$(printf '%s' "$LINE" | sed -E 's#https://[^@]+@([^/]+).*#\1#')"
|
||||||
|
BASE="https://${HOST}"
|
||||||
|
|
||||||
|
if [ -z "$USER" ] || [ -z "$TOKEN" ] || [ -z "$HOST" ]; then
|
||||||
|
echo "Konnte User/Token/Host nicht aus ~/.git-credentials lesen." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
RESP="$(mktemp)"; trap 'rm -f "$RESP"' EXIT
|
||||||
|
CODE="$(curl -s -o "$RESP" -w '%{http_code}' -X POST "$BASE/api/v1/user/repos" \
|
||||||
|
-H "Authorization: token $TOKEN" -H "Content-Type: application/json" \
|
||||||
|
-d "$(python3 -c 'import json,sys; print(json.dumps({"name":sys.argv[1],"description":sys.argv[2],"private":True,"auto_init":True,"default_branch":"main"}))' "$NAME" "$BESCHREIBUNG")")"
|
||||||
|
|
||||||
|
case "$CODE" in
|
||||||
|
201)
|
||||||
|
CLONE="$(python3 -c 'import json,sys; print(json.load(open(sys.argv[1])).get("clone_url",""))' "$RESP" 2>/dev/null)"
|
||||||
|
FULL="$(python3 -c 'import json,sys; print(json.load(open(sys.argv[1])).get("full_name",""))' "$RESP" 2>/dev/null)"
|
||||||
|
mkdir -p "$(dirname "$LOG")"
|
||||||
|
echo "$(date '+%Y-%m-%d %H:%M') angelegt (privat): $FULL" >> "$LOG"
|
||||||
|
# Stiller Chronik-Spiegel (Audit-Spur, wie die Radar-Meldungen)
|
||||||
|
curl -sf -m 5 -X POST "${MC_ANNOUNCE_URL:-http://127.0.0.1:9001/api/voice/announce}" \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
--data "$(python3 -c 'import json,sys; print(json.dumps({"text":"Neues PRIVATES Projekt-Repo angelegt: "+sys.argv[1],"subject":"Gitea","source":"gitea-repo-create","priority":"silent"}))' "$FULL")" \
|
||||||
|
>/dev/null 2>&1 || true
|
||||||
|
echo "Repo '$FULL' angelegt (privat, main initialisiert)."
|
||||||
|
echo "CLONE ${CLONE}"
|
||||||
|
exit 0 ;;
|
||||||
|
403)
|
||||||
|
if grep -q 'write:user' "$RESP"; then
|
||||||
|
echo "FEHLT: Das gespeicherte Gitea-Token darf keine Repos anlegen (Scope 'write:user' fehlt)." >&2
|
||||||
|
echo "So wird es freigeschaltet (einmalig, durch den Commander):" >&2
|
||||||
|
echo " Gitea → Einstellungen → Anwendungen → neues Token mit Scopes 'write:repository' UND 'write:user'," >&2
|
||||||
|
echo " dann in ~/.git-credentials das alte Token ersetzen. Danach funktioniert dieses Skript." >&2
|
||||||
|
else
|
||||||
|
echo "403 von Gitea:" >&2; head -c 300 "$RESP" >&2; echo >&2
|
||||||
|
fi
|
||||||
|
exit 3 ;;
|
||||||
|
409)
|
||||||
|
echo "Ein Repo namens '$NAME' existiert bereits." >&2
|
||||||
|
exit 4 ;;
|
||||||
|
*)
|
||||||
|
echo "Gitea antwortete mit HTTP $CODE:" >&2; head -c 300 "$RESP" >&2; echo >&2
|
||||||
|
exit 1 ;;
|
||||||
|
esac
|
||||||
Reference in New Issue
Block a user