Initial commit

This commit is contained in:
marcus.hinz
2026-07-09 09:21:53 +02:00
commit a5671a9b52
649 changed files with 35326 additions and 0 deletions
Executable
+84
View File
@@ -0,0 +1,84 @@
#!/usr/bin/env bash
# git-sync — add/commit/pull --rebase/push.
# git-sync alle Repos aus permissions.additionalDirectories
# git-sync <dir> [message] ein einzelnes Repo
# Safe: rebaset auf den Remote, kein Merge, kein force-push; Konflikte werden
# gemeldet (Rebase abgebrochen), nicht automatisch aufgelöst.
set -uo pipefail
ok() { printf '\033[1;32m✓ %s\033[0m\n' "$*"; } # green
note() { printf '\033[1;36m· %s\033[0m\n' "$*"; } # cyan
warn() { printf '\033[1;33m⚠ %s\033[0m\n' "$*"; } # yellow
sync_one() {
local dir=$1 msg=${2:-} label branch ahead behind
case "$dir" in "~") dir="$HOME" ;; "~/"*) dir="$HOME/${dir#"~/"}" ;; esac
label=$(basename "$dir")
if ! git -C "$dir" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
warn "$label: kein Git-Repo — übersprungen."; return 0
fi
branch=$(git -C "$dir" rev-parse --abbrev-ref HEAD)
# add/commit
if [ -n "$(git -C "$dir" status --porcelain)" ]; then
git -C "$dir" add -A
[ -z "$msg" ] && msg="git-sync: $(date '+%Y-%m-%d %H:%M')"
if git -C "$dir" commit --quiet -m "$msg"; then
note "$label: committed — $msg"
else
warn "$label: commit fehlgeschlagen."; return 0
fi
else
note "$label: keine Änderungen."
fi
# pull --rebase, dann push
if ! git -C "$dir" remote get-url origin >/dev/null 2>&1; then
note "$label: kein origin-Remote — push übersprungen."; return 0
fi
if git -C "$dir" rev-parse --abbrev-ref --symbolic-full-name '@{u}' >/dev/null 2>&1; then
git -C "$dir" fetch --quiet 2>/dev/null || true
behind=$(git -C "$dir" rev-list --count 'HEAD..@{u}' 2>/dev/null || echo 0)
if [ "$behind" -gt 0 ]; then
if git -C "$dir" pull --rebase --quiet 2>/dev/null; then
note "$label: $behind Commit(s) per Rebase integriert."
else
git -C "$dir" rebase --abort >/dev/null 2>&1 || true
warn "$label: Pull/Rebase-Konflikt — bitte manuell lösen. Push übersprungen."; return 0
fi
fi
ahead=$(git -C "$dir" rev-list --count '@{u}..HEAD' 2>/dev/null || echo 0)
if [ "$ahead" -eq 0 ]; then
note "$label: nichts zu pushen."
elif git -C "$dir" push --quiet 2>/dev/null; then
ok "$label: $ahead Commit(s) gepusht ($branch)."
else
warn "$label: push abgelehnt — Remote voraus. Manuell prüfen."
fi
else
if git -C "$dir" push --quiet -u origin "$branch" 2>/dev/null; then
ok "$label: Upstream gesetzt und gepusht ($branch)."
else
warn "$label: kein Upstream, push fehlgeschlagen — einmal manuell pushen."
fi
fi
}
# --- dispatch --------------------------------------------------------------
if [ $# -ge 1 ]; then
sync_one "$1" "${2:-}"
exit 0
fi
# ohne Argument: alle additionalDirectories aus den Settings (cwd + User)
dirs=$(for f in .claude/settings.json .claude/settings.local.json "$HOME/.claude/settings.json"; do
[ -f "$f" ] && jq -r '.permissions.additionalDirectories[]?' "$f" 2>/dev/null
done | sort -u)
if [ -z "$dirs" ]; then
note "keine additionalDirectories gefunden (cwd: $PWD)"; exit 0
fi
while IFS= read -r d; do
[ -n "$d" ] && sync_one "$d"
done <<< "$dirs"
+16
View File
@@ -0,0 +1,16 @@
#!/usr/bin/env bash
# link-pool-runtime <pool> — hängt projects/todos/history.jsonl eines Pools auf
# das synced Repo (~/claude-projects/pool/<pool>/) um. Verwirft vorhandenen
# Inhalt. NUR bei idlem Pool laufen (keine offene Session).
set -euo pipefail
pool=${1:?Aufruf: link-pool-runtime <pool>}
SRC="$HOME/.config/ai-control/pools/$pool"
DATA="$HOME/claude-projects/pool/$pool"
[ -d "$SRC" ] || { echo "Pool fehlt: $SRC" >&2; exit 1; }
mkdir -p "$DATA/projects" "$DATA/todos"
[ -e "$DATA/history.jsonl" ] || : > "$DATA/history.jsonl"
for n in projects todos history.jsonl; do
if [ -d "$SRC/$n" ] && [ ! -L "$SRC/$n" ]; then rm -rf "$SRC/$n"; else rm -f "$SRC/$n"; fi
ln -s "$DATA/$n" "$SRC/$n"
done
echo "verlinkt: $pool"
+55
View File
@@ -0,0 +1,55 @@
#!/usr/bin/env bash
# new-project — scaffold a new claude-projects project + matching ~/projects dir,
# register it, then commit & push claude-projects.
# Usage: new-project <name>
set -euo pipefail
name=${1:?usage: new-project <name>}
case "$name" in
*/* | *" "* | .*) echo "ungültiger Name: $name" >&2; exit 1 ;;
esac
cproot="$HOME/claude-projects"
root="$cproot/$name"
[ -e "$root" ] && { echo "existiert bereits: $root" >&2; exit 1; }
# 1. Code-Verzeichnis unter ~/projects
mkdir -p "$HOME/projects/$name"
# 2. claude-projects-Scaffold
mkdir -p "$root/.claude" "$root/memory"
cat > "$root/.claude/settings.json" <<EOF
{
"autoMemoryDirectory": "~/claude-projects/$name/memory",
"permissions": {
"allow": [
"Edit(~/projects/$name/**)",
"Edit(~/claude-projects/$name/**)"
],
"additionalDirectories": [
"~/projects/$name"
]
}
}
EOF
cat > "$root/.claude/settings.local.json" <<'EOF'
{
"permissions": {
"allow": []
}
}
EOF
printf '# Memory Index\n' > "$root/memory/MEMORY.md"
# 3. claude-projects committen & pushen (nur den neuen Projektordner)
git -C "$cproot" add "$name"
git -C "$cproot" commit -q -m "new project: $name"
git -C "$cproot" push -q
echo "angelegt:"
echo " ~/projects/$name (Code-Verzeichnis)"
echo " ~/claude-projects/$name (.claude/settings*, memory/MEMORY.md)"
echo " registriert in additionalDirectories + Edit-Regeln, committet & gepusht"