From 7e19208061065b83b671f4a6ef56c82d57bf830e Mon Sep 17 00:00:00 2001 From: Barby Date: Thu, 9 Jul 2026 16:02:36 +0200 Subject: [PATCH] Initial: GPU1-Hooks + Auto-Update + Deploy-Script --- deploy.sh | 25 ++++++++ hooks-v2/gpu1-master-workflow.sh | 25 ++++++++ hooks-v2/sessionstart-hook-autoupdate.sh | 33 ++++++++++ hooks-v2/stop-chat-snapshot.sh | 76 ++++++++++++++++++++++++ hooks-v2/sync-chat-status-gitlab.sh | 18 ++++++ 5 files changed, 177 insertions(+) create mode 100644 deploy.sh create mode 100755 hooks-v2/gpu1-master-workflow.sh create mode 100644 hooks-v2/sessionstart-hook-autoupdate.sh create mode 100755 hooks-v2/stop-chat-snapshot.sh create mode 100755 hooks-v2/sync-chat-status-gitlab.sh diff --git a/deploy.sh b/deploy.sh new file mode 100644 index 0000000..eb3860f --- /dev/null +++ b/deploy.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# Claude Hooks Deploy — läuft auf jedem neuen Mac/Hub-Instanz einmalig +# curl -sL https://git.consoro.eu/barby/claude-hooks/raw/branch/main/deploy.sh | bash + +set -e +HOOKS_REPO="https://barby:dc9a2241890acb243548342977a6c02d6dde39a7@git.consoro.eu/barby/claude-hooks.git" +CLAUDE_DIR="$HOME/.claude" +HOOKS_DIR="$CLAUDE_DIR/hooks-v2" +LOCAL_REPO="$HOME/git/claude-hooks" + +echo "=== Claude Hooks Deploy ===" +mkdir -p "$HOOKS_DIR" "$LOCAL_REPO" + +if [ ! -d "$LOCAL_REPO/.git" ]; then + git clone "$HOOKS_REPO" "$LOCAL_REPO" +else + cd "$LOCAL_REPO" && git pull origin main -q +fi + +# Scripts deployen +cp "$LOCAL_REPO/hooks-v2/"*.sh "$HOOKS_DIR/" 2>/dev/null +chmod +x "$HOOKS_DIR/"*.sh + +echo "✅ $(ls $HOOKS_DIR/*.sh | wc -l | tr -d ' ') Hook-Scripts deployed nach $HOOKS_DIR" +echo "Fertig — bitte Claude Code neu starten." diff --git a/hooks-v2/gpu1-master-workflow.sh b/hooks-v2/gpu1-master-workflow.sh new file mode 100755 index 0000000..af187bc --- /dev/null +++ b/hooks-v2/gpu1-master-workflow.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# GPU1-Shadow-Portal MASTER Workflow Hook +# Läuft bei jedem UserPromptSubmit wenn CWD = Claude_desktop Projekt + +MASTER="/Users/matthiaskoerner/Library/Mobile Documents/iCloud~md~obsidian/Documents/GPU1-Shadow-Portal-MASTER-2026-07.md" + +# Nur aktiv wenn wir im richtigen Projekt sind +CWD_CHECK="${CLAUDE_PROJECT_DIR:-$PWD}" +if [[ "$CWD_CHECK" != *"Claude_desktop"* ]]; then + exit 0 +fi + +if [ ! -f "$MASTER" ]; then + echo "⚠️ MASTER-DOK FEHLT: $MASTER" + exit 0 +fi + +# Letztes Update + offene Tasks zählen +LAST_MOD=$(stat -f "%Sm" -t "%d.%m %H:%M" "$MASTER" 2>/dev/null || echo "?") +OPEN=$(grep -c "^\- \[ \]" "$MASTER" 2>/dev/null || echo "?") +IN_PROG=$(grep -c "🔄\|in_progress\|⏳" "$MASTER" 2>/dev/null || echo "0") + +echo "📋 MASTER-PROTOKOLL: GPU1-Shadow-Portal-MASTER-2026-07.md" +echo " Letztes Update: $LAST_MOD | Offene Tasks: $OPEN | In Arbeit: $IN_PROG" +echo " WORKFLOW-PFLICHT: (1) MASTER lesen → (2) Plan mit Bär besprechen → (3) GO abwarten → (4) /swarm → (5) Funktionstest → (6) MASTER+Obsidian+GitLab updaten" diff --git a/hooks-v2/sessionstart-hook-autoupdate.sh b/hooks-v2/sessionstart-hook-autoupdate.sh new file mode 100644 index 0000000..01db1b9 --- /dev/null +++ b/hooks-v2/sessionstart-hook-autoupdate.sh @@ -0,0 +1,33 @@ +#!/bin/bash +# SessionStart: Hook-Scripts automatisch vom Hub aktualisieren (max 1x/Stunde) +LOCK="/tmp/claude-hooks-update.lock" +LOCAL_REPO="$HOME/git/claude-hooks" +HOOKS_DIR="$HOME/.claude/hooks-v2" +LAST_UPDATE="$HOME/.claude/hooks-v2/.last-update" + +# Max 1x pro Stunde updaten +if [ -f "$LAST_UPDATE" ]; then + LAST=$(cat "$LAST_UPDATE" 2>/dev/null || echo 0) + NOW=$(date +%s) + DIFF=$((NOW - LAST)) + [ $DIFF -lt 3600 ] && exit 0 +fi + +# Nicht parallel laufen +[ -f "$LOCK" ] && exit 0 +touch "$LOCK" +trap "rm -f $LOCK" EXIT + +if [ -d "$LOCAL_REPO/.git" ]; then + cd "$LOCAL_REPO" + BEFORE=$(git rev-parse HEAD 2>/dev/null) + git pull origin main -q 2>/dev/null + AFTER=$(git rev-parse HEAD 2>/dev/null) + if [ "$BEFORE" != "$AFTER" ]; then + cp "$LOCAL_REPO/hooks-v2/"*.sh "$HOOKS_DIR/" 2>/dev/null + chmod +x "$HOOKS_DIR/"*.sh + echo "🔄 Claude Hooks aktualisiert von Hub" + fi +fi + +date +%s > "$LAST_UPDATE" diff --git a/hooks-v2/stop-chat-snapshot.sh b/hooks-v2/stop-chat-snapshot.sh new file mode 100755 index 0000000..35fe9d6 --- /dev/null +++ b/hooks-v2/stop-chat-snapshot.sh @@ -0,0 +1,76 @@ +#!/bin/bash +# Stop-Hook: Chat-Snapshot nach jeder Antwort — NUR für Claude_desktop Projekt + +CWD_CHECK="${CLAUDE_PROJECT_DIR:-$PWD}" +if [[ "$CWD_CHECK" != *"Claude_desktop"* ]]; then + exit 0 +fi + +PROJECT_DIR="/Users/matthiaskoerner/Library/Mobile Documents/com~apple~CloudDocs/Claude_desktop" +STATUS_MD="$PROJECT_DIR/status.md" +JSONL_DIR="/Users/matthiaskoerner/.claude/projects/-Users-matthiaskoerner-Library-Mobile-Documents-com-apple-CloudDocs-Claude-desktop" + +JSONL=$(ls -t "$JSONL_DIR"/*.jsonl 2>/dev/null | head -1) +[ -z "$JSONL" ] && exit 0 + +python3 - "$JSONL" "$STATUS_MD" << 'PYEOF' +import sys, json, os +from datetime import datetime + +jsonl_path, out_path = sys.argv[1], sys.argv[2] + +lines = [] +try: + with open(jsonl_path) as f: + lines = f.readlines() +except: + sys.exit(0) + +msgs = [] +for line in lines[-60:]: + try: + entry = json.loads(line) + if entry.get("type") == "user": + msg = entry.get("message", {}) + txt = "" + if isinstance(msg.get("content"), str): + txt = msg["content"] + elif isinstance(msg.get("content"), list): + for c in msg["content"]: + if isinstance(c, dict) and c.get("type") == "text": + txt += c.get("text", "") + if txt.strip(): + msgs.append(("Bär", txt.strip()[:600])) + elif entry.get("type") == "assistant": + msg = entry.get("message", {}) + txt = "" + if isinstance(msg.get("content"), list): + for c in msg["content"]: + if isinstance(c, dict) and c.get("type") == "text": + txt += c.get("text", "") + if txt.strip(): + msgs.append(("Barby", txt.strip()[:1000])) + except: + continue + +if not msgs: + sys.exit(0) + +existing = "" +if os.path.exists(out_path): + with open(out_path) as f: + existing = f.read() + +last_txt = msgs[-1][1] if msgs else "" +if last_txt and last_txt[:80] in existing[-3000:]: + sys.exit(0) # kein Duplikat + +ts = datetime.now().strftime("%Y-%m-%d %H:%M:%S") +content = f"\n---\n### {ts}\n" +for role, text in msgs[-4:]: + icon = "🧔" if role == "Bär" else "🤖" + content += f"**{icon} {role}:** {text}\n\n" + +with open(out_path, "a") as f: + f.write(content) +PYEOF diff --git a/hooks-v2/sync-chat-status-gitlab.sh b/hooks-v2/sync-chat-status-gitlab.sh new file mode 100755 index 0000000..f9f4b74 --- /dev/null +++ b/hooks-v2/sync-chat-status-gitlab.sh @@ -0,0 +1,18 @@ +#!/bin/bash +# Alle 2min: status.md aus Claude_desktop → git.consoro.eu/barby/claude-chat-status + +STATUS_SRC="/Users/matthiaskoerner/Library/Mobile Documents/com~apple~CloudDocs/Claude_desktop/status.md" +REPO_DIR="/Users/matthiaskoerner/git/claude-chat-status" + +[ ! -f "$STATUS_SRC" ] && exit 0 + +cp "$STATUS_SRC" "$REPO_DIR/status.md" + +cd "$REPO_DIR" || exit 1 +git add status.md +if git diff --cached --quiet; then + exit 0 # nix geändert +fi + +git commit -m "auto-sync $(date '+%H:%M:%S')" --author="Barby " -q +git push origin main -q 2>&1 | logger -t claude-chat-sync