Files
claude-werkzeuge/.vault-tools/auto-push/taeglich_push.py
T
Pascal Michel dd5e612452 Abgleich mit dem Vault-Stand 80a20f1
6 Datei(en) geändert.
Erzeugt von .vault-tools/auto-push/werkzeuge_spiegel.py.
2026-10-15 04:00:03 +02:00

127 lines
4.3 KiB
Python

"""Täglicher Lauf: committet und pusht die Anweisungsschicht und spiegelt die Werkzeuge.
Ersteller: Pascal Michel
Erstellt: 2026-09-17
Geändert: 2026-10-14 (Werkzeug-Spiegel nach claude-werkzeuge)
WARUM LOKAL UND NICHT ALS COWORK-ROUTINE
Eine Cowork-Routine läuft in Anthropics Cloud und hat weder Zugriff auf
D:\\Claude noch auf die Umgebungsvariable GITEA_TOKEN dieser Maschine (so
wörtlich in der Routinen-Doku, gelesen am 2026-09-17). Sie könnte hier
nichts committen. Deshalb die Windows-Aufgabenplanung.
WAS ES TUT
1. Genau dasselbe wie der frühere PostToolUse-Hook: die Arbeitsfunktion
aus auto_push.py, unter derselben Sperre. Der Umfang steht in der
.gitignore des Vault-Roots, nicht hier.
2. Danach, noch unter der Sperre, spiegelt werkzeuge_spiegel.py den
committeten Stand von .vault-tools/ und .claude/ in das öffentliche
Repo claude-werkzeuge. Scheitert Schritt 1, entfällt Schritt 2.
WAS ES MELDET
Jeder Lauf schreibt eine Zeile je Schritt nach lauf.log im selben Ordner,
auch ein Lauf ohne Änderung. Eine Protokolldatei, die nur bei Erfolg
schreibt, lässt sich von einer nicht gestarteten Aufgabe nicht
unterscheiden, und genau das war am 2026-09-07 beim Depotbericht das
Problem.
Exit 0: gepusht oder nichts zu tun, in beiden Schritten. Exit 1: Befund in
einem Schritt, Text steht im Protokoll. Die Aufgabenplanung zeigt den Code
als „Letztes Ergebnis".
"""
from __future__ import annotations
import importlib.util
import sys
import traceback
from datetime import datetime
from pathlib import Path
HIER = Path(__file__).resolve().parent
PROTOKOLL = HIER / "lauf.log"
MAX_PROTOKOLL_ZEILEN = 400
def lade(name: str):
spec = importlib.util.spec_from_file_location(name, HIER / f"{name}.py")
if spec is None or spec.loader is None:
raise RuntimeError(f"{name}.py nicht ladbar: {HIER / f'{name}.py'}")
modul = importlib.util.module_from_spec(spec)
spec.loader.exec_module(modul)
return modul
def schreibe(zeile: str) -> None:
stempel = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
text = f"{stempel} {zeile}\n"
try:
alt = PROTOKOLL.read_text(encoding="utf-8").splitlines(keepends=True)
except OSError:
alt = []
alt.append(text)
PROTOKOLL.write_text("".join(alt[-MAX_PROTOKOLL_ZEILEN:]), encoding="utf-8")
sys.stdout.write(text)
def vault_push(hook, wurzel: Path) -> int:
try:
vorher = hook.git(wurzel, "rev-parse", "HEAD").strip()
hook.arbeite(wurzel)
nachher = hook.git(wurzel, "rev-parse", "HEAD").strip()
except hook.GitFehler as fehler:
schreibe(f"BEFUND {fehler.kopf} | {' '.join(fehler.rumpf.split())[:400]}")
return 1
except Exception as fehler: # noqa: BLE001
schreibe(f"BEFUND unerwarteter Abbruch: {type(fehler).__name__}: {fehler}")
schreibe(" " + " ".join(traceback.format_exc().split())[:400])
return 1
if vorher == nachher:
schreibe(f"ok nichts zu tun, HEAD {nachher[:8]}")
else:
schreibe(f"ok gepusht, HEAD {vorher[:8]} -> {nachher[:8]}")
return 0
def werkzeuge_spiegeln(wurzel: Path) -> int:
try:
spiegel = lade("werkzeuge_spiegel")
status, text = spiegel.spiegele(wurzel)
except Exception as fehler: # noqa: BLE001 - SpiegelFehler und jeder Absturz sind Befunde
schreibe(f"BEFUND werkzeuge: {type(fehler).__name__}: {' '.join(str(fehler).split())[:400]}")
return 1
schreibe(f"ok werkzeuge {status}, {text}")
return 0
def main() -> int:
try:
hook = lade("auto_push")
except Exception as fehler: # noqa: BLE001
schreibe(f"BEFUND auto_push.py nicht ladbar: {type(fehler).__name__}: {fehler}")
return 1
wurzel = HIER.parents[1]
sperre = wurzel / hook.SPERRE_REL
deskriptor = hook.hole_sperre(sperre)
if deskriptor is None:
# Kein Befund: ein anderer Lauf arbeitet und nimmt alles mit.
schreibe("uebersprungen Sperre belegt, ein anderer Lauf arbeitet")
return 0
try:
if vault_push(hook, wurzel) != 0:
return 1
return werkzeuge_spiegeln(wurzel)
finally:
hook.gib_sperre_frei(deskriptor, sperre)
if __name__ == "__main__":
try:
sys.stdout.reconfigure(encoding="utf-8")
except AttributeError:
pass
raise SystemExit(main())