"""Täglicher Lauf: committet und pusht die Anweisungsschicht, für die Windows-Aufgabenplanung. Ersteller: Pascal Michel Erstellt: 2026-09-17 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 Genau dasselbe wie der PostToolUse-Hook: die Arbeitsfunktion aus auto_push.py, unter derselben Sperre. Der Umfang steht in der .gitignore des Vault-Roots, nicht hier. WAS ES MELDET Jeder Lauf schreibt eine Zeile 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. Exit 1: Befund, 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_hook(): spec = importlib.util.spec_from_file_location("auto_push", HIER / "auto_push.py") if spec is None or spec.loader is None: raise RuntimeError(f"auto_push.py nicht ladbar: {HIER / 'auto_push.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 main() -> int: try: hook = lade_hook() 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: 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 finally: hook.gib_sperre_frei(deskriptor, sperre) if vorher == nachher: schreibe(f"ok nichts zu tun, HEAD {nachher[:8]}") else: schreibe(f"ok gepusht, HEAD {vorher[:8]} -> {nachher[:8]}") return 0 if __name__ == "__main__": try: sys.stdout.reconfigure(encoding="utf-8") except AttributeError: pass raise SystemExit(main())