feat(dev_session): Add agent-driven Notion status reporting

Implements the  functionality in , allowing the Gemini agent to non-interactively update a Notion task with a detailed progress summary.

The agent can now be prompted to:
- Collect the new task status and any open to-dos.
- Generate a summary of Git changes () and commit messages.
- Post a formatted report as a comment to the Notion task.
- Update the task's status property.

The  has been updated to document this new agent-centric workflow, detailing how to start a session, work within it, and use the agent to report progress and push changes seamlessly.
This commit is contained in:
2026-01-26 12:24:26 +00:00
parent 4afadc2c26
commit d1ff433597
2 changed files with 214 additions and 95 deletions

View File

@@ -412,9 +412,152 @@ def select_task(token: str, project_id: str, tasks_db_id: str) -> Optional[Dict]
print("Ungültige Eingabe. Bitte eine Zahl eingeben.")
import subprocess
from datetime import datetime
# --- Git Summary Generation ---
def generate_git_summary() -> Tuple[str, str]:
"""Generiert eine Zusammenfassung der Git-Änderungen und Commit-Nachrichten seit dem letzten Push zum Main-Branch."""
try:
# Finde den aktuellen Main-Branch Namen (master oder main)
try:
main_branch = subprocess.check_output(["git", "rev-parse", "--abbrev-ref", "HEAD"]).decode("utf-8").strip()
if main_branch not in ["main", "master"]:
# Versuche, den Remote-Tracking-Branch für main/master zu finden
result = subprocess.run(["git", "branch", "-r"], capture_output=True, text=True)
if "origin/main" in result.stdout:
main_branch = "origin/main"
elif "origin/master" in result.stdout:
main_branch = "origin/master"
else:
print("Warnung: Konnte keinen 'main' oder 'master' Branch finden. Git-Zusammenfassung wird möglicherweise unvollständig sein.")
main_branch = "HEAD~1" # Fallback zum letzten Commit, falls kein Main-Branch gefunden wird
except subprocess.CalledProcessError:
main_branch = "HEAD~1" # Fallback, falls gar kein Branch gefunden wird
# Git diff --stat
diff_stat_cmd = ["git", "diff", "--stat", f"{main_branch}...HEAD"]
diff_stat = subprocess.check_output(diff_stat_cmd).decode("utf-8").strip()
# Git log --pretty
commit_log_cmd = ["git", "log", "--pretty=format:- %s", f"{main_branch}...HEAD"]
commit_messages = subprocess.check_output(commit_log_cmd).decode("utf-8").strip()
return diff_stat, commit_messages
except subprocess.CalledProcessError as e:
print(f"❌ FEHLER beim Generieren der Git-Zusammenfassung: {e}")
return "", ""
# --- Report Status to Notion ---
def report_status_to_notion(
status_override: Optional[str],
todos_override: Optional[str],
git_changes_override: Optional[str],
commit_messages_override: Optional[str]
) -> None:
"""
Erstellt einen Statusbericht für den Notion-Task, entweder interaktiv oder mit überschriebenen Werten.
"""
if not os.path.exists(SESSION_FILE_PATH):
print("❌ FEHLER: Keine aktive Session gefunden. Kann keinen Statusbericht erstellen.")
return
try:
with open(SESSION_FILE_PATH, "r") as f:
session_data = json.load(f)
task_id = session_data.get("task_id")
token = session_data.get("token")
if not (task_id and token):
print("❌ FEHLER: Session-Daten unvollständig. Kann keinen Statusbericht erstellen.")
return
print(f"--- Erstelle Statusbericht für Task {task_id} ---")
# Git-Zusammenfassung generieren (immer, wenn nicht explizit überschrieben)
actual_git_changes = git_changes_override
actual_commit_messages = commit_messages_override
if not git_changes_override or not commit_messages_override:
print("Generiere Git-Zusammenfassung...")
diff_stat, commit_log = generate_git_summary()
if not git_changes_override:
actual_git_changes = diff_stat
if not commit_messages_override:
actual_commit_messages = commit_log
# Status abfragen oder übernehmen
actual_status = status_override
if not actual_status:
tasks_db_id = find_database_by_title(token, "Tasks [UT]")
if tasks_db_id:
status_options = get_database_status_options(token, tasks_db_id)
if status_options:
print("\nBitte wähle den neuen Status des Tasks:")
for i, option in enumerate(status_options):
print(f"[{i+1}] {option}")
while True:
try:
choice = int(input("Wähle eine Nummer: "))
if 1 <= choice <= len(status_options):
actual_status = status_options[choice - 1]
break
else:
print("Ungültige Auswahl.")
except ValueError:
print("Ungültige Eingabe. Bitte eine Zahl eingeben.")
else:
print("Warnung: Konnte Status-Optionen nicht abrufen. Bitte Status manuell eingeben.")
actual_status = input("Bitte gib den neuen Status manuell ein: ")
if not actual_status:
print("❌ FEHLER: Kein Status festgelegt. Abbruch des Berichts.")
return
# To-Dos abfragen oder übernehmen
actual_todos = todos_override
if not actual_todos:
user_todos = input("\nGibt es offene To-Dos oder nächste Schritte? (Leer lassen zum Überspringen): ")
actual_todos = user_todos.strip()
# Kommentar zusammenstellen
report_lines = []
report_lines.append(f"**Status Update ({datetime.now().strftime('%Y-%m-%d %H:%M')})**")
report_lines.append(f"**Neuer Status:** `{actual_status}`")
if actual_git_changes or actual_commit_messages:
report_lines.append("\n**Zusammenfassung der Änderungen:**")
if actual_git_changes:
report_lines.append("```diff")
report_lines.append(actual_git_changes)
report_lines.append("```")
if actual_commit_messages:
report_lines.append("\n**Commit Nachrichten:**")
report_lines.append("```")
report_lines.append(actual_commit_messages)
report_lines.append("```")
if actual_todos:
report_lines.append("\n**Offene To-Dos / Nächste Schritte:**")
# Sicherstellen, dass To-Dos als Liste oder einzelne Zeilen formatiert sind
for todo_item in actual_todos.split('\n'):
report_lines.append(f"- {todo_item.strip()}")
notion_comment = "\n".join(report_lines)
# Notion aktualisieren
add_comment_to_notion_task(token, task_id, notion_comment)
update_notion_task_status(token, task_id, actual_status)
except (FileNotFoundError, json.JSONDecodeError) as e:
print(f"❌ FEHLER beim Lesen der Session-Informationen für Statusbericht: {e}")
except Exception as e:
print(f"❌ Unerwarteter Fehler beim Erstellen des Statusberichts: {e}")
# --- Context Generation ---
def generate_cli_context(project_title: str, task_title: str, task_id: str, readme_path: Optional[str], task_description: Optional[str]) -> str:
"""Erstellt den reinen Kontext-String für die Gemini CLI."""
@@ -613,6 +756,11 @@ def main():
parser = argparse.ArgumentParser(description="Interaktiver Session-Manager für die Gemini-Entwicklung mit Notion-Integration.")
parser.add_argument("--done", action="store_true", help="Schließt die aktuelle Entwicklungs-Session ab.")
parser.add_argument("--add-comment", type=str, help="Fügt einen Kommentar zum aktuellen Notion-Task hinzu.")
parser.add_argument("--report-status", action="store_true", help="Erstellt einen Statusbericht für den Notion-Task.")
parser.add_argument("--status", type=str, help="Status, der im Notion-Task gesetzt werden soll (z.B. 'In Bearbeitung', 'Bereit für Review').")
parser.add_argument("--todos", type=str, help="Eine durch '\n' getrennte Liste offener To-Dos.")
parser.add_argument("--git-changes", type=str, help="Zusammenfassung der Git-Änderungen (git diff --stat).")
parser.add_argument("--commit-messages", type=str, help="Eine durch '\n' getrennte Liste der Commit-Nachrichten.")
args = parser.parse_args()
@@ -634,6 +782,8 @@ def main():
print("❌ FEHLER: Session-Daten unvollständig. Kann keinen Kommentar hinzufügen.")
except (FileNotFoundError, json.JSONDecodeError):
print("❌ FEHLER: Fehler beim Lesen der Session-Informationen. Kann keinen Kommentar hinzufügen.")
elif args.report_status:
report_status_to_notion(args.status, args.todos, args.git_changes, args.commit_messages)
else:
start_interactive_session()