Files
claude-regelwerk/.claude/skills/plane-abgleich/scripts/plane/zustand.py
T
Pascal MichelandClaude Opus 5 2c9a4475fc Regelwerk, Agenten, Skills und Werkzeuge veröffentlichen
Erster Stand des öffentlichen Ausschnitts aus dem Vault. Die .gitignore
arbeitet als Positivliste: ausgeschlossen ist alles, eingeschlossen nur,
was ausdrücklich wieder aufgenommen wird. Notizen, Projekte, Finanzen,
das Sitzungsgedächtnis und settings.local.json bleiben damit außen vor.

Der Kundenname in AI/Regelwerk/seo.md ist durch eine neutrale
Bezeichnung ersetzt; die Regeln selbst sind unverändert.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-17 22:38:15 +02:00

78 lines
2.5 KiB
Python

"""Der Stand des letzten Laufs — die Basis des Drei-Wege-Vergleichs."""
from __future__ import annotations
import json
from datetime import datetime
from pathlib import Path
from .abgleich import Basiseintrag
DATEINAME = ".plane-sync.json"
VERSION = 1
class Zustand:
def __init__(self, pfad: Path, roh: dict, warnung: str | None = None):
self.pfad = pfad
self.warnung = warnung
self.plane_projekt: str | None = roh.get("plane_project")
self.eintraege: dict[str, Basiseintrag] = {
marker: Basiseintrag(
marker=marker,
work_item_id=werte["work_item_id"],
titel=werte["titel"],
erledigt=bool(werte["erledigt"]),
)
for marker, werte in (roh.get("eintraege") or {}).items()
}
self._letzter_lauf: str | None = roh.get("letzter_lauf")
def setze(self, eintrag: Basiseintrag) -> None:
"""Trägt einen Eintrag ein und speichert sofort — das macht den Lauf wiederaufsetzbar."""
self.eintraege[eintrag.marker] = eintrag
self.speichere()
def entferne_marker(self, marker: str) -> None:
self.eintraege.pop(marker, None)
self.speichere()
def setze_lauf_zeit(self) -> None:
self._letzter_lauf = datetime.now().astimezone().isoformat(timespec="seconds")
self.speichere()
def speichere(self) -> None:
inhalt = {
"version": VERSION,
"plane_project": self.plane_projekt,
"letzter_lauf": self._letzter_lauf,
"eintraege": {
marker: {
"work_item_id": e.work_item_id,
"titel": e.titel,
"erledigt": e.erledigt,
}
for marker, e in sorted(self.eintraege.items())
},
}
self.pfad.write_text(
json.dumps(inhalt, ensure_ascii=False, indent=2) + "\n", encoding="utf-8"
)
def lies(pfad: Path) -> Zustand:
pfad = Path(pfad)
if not pfad.exists():
return Zustand(pfad, {})
try:
return Zustand(pfad, json.loads(pfad.read_text(encoding="utf-8")))
except (json.JSONDecodeError, KeyError, TypeError) as fehler:
return Zustand(
pfad,
{},
warnung=(
f"{pfad} ist unlesbar ({fehler}). Der Lauf behandelt sie als leer; "
"dadurch erscheinen bereits abgeglichene Aufgaben erneut."
),
)