Compare commits
1 Commits
main
...
feature/ta
| Author | SHA1 | Date | |
|---|---|---|---|
| bb918a8839 |
@@ -1 +1 @@
|
||||
{"task_id": "2f488f42-8544-819a-8407-f29748b3e0b8", "token": "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"}
|
||||
{"task_id": "2f488f42-8544-81ac-a9f8-e373c4c18115", "token": "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", "session_start_time": "2026-01-26T18:39:11.157549"}
|
||||
170
dev_session.py
170
dev_session.py
@@ -1,10 +1,14 @@
|
||||
import re
|
||||
from typing import List, Dict, Optional, Tuple, Any
|
||||
from getpass import getpass
|
||||
from dotenv import load_dotenv
|
||||
import subprocess
|
||||
from datetime import datetime, timedelta
|
||||
import os
|
||||
import requests
|
||||
import json
|
||||
import re
|
||||
from typing import List, Dict, Optional, Tuple
|
||||
from getpass import getpass
|
||||
from dotenv import load_dotenv
|
||||
import argparse
|
||||
import shutil
|
||||
|
||||
load_dotenv()
|
||||
|
||||
@@ -83,18 +87,48 @@ def get_page_title(page: Dict) -> str:
|
||||
return title_parts[0].get("plain_text", "Unbenannt")
|
||||
return "Unbenannt"
|
||||
|
||||
def get_page_property(page: Dict, prop_name: str, prop_type: str = "rich_text") -> Optional[str]:
|
||||
def get_page_rich_text_property(page: Dict, prop_name: str) -> Optional[str]:
|
||||
"""Extrahiert den Inhalt einer bestimmten Eigenschaft (Property) von einer Seite."""
|
||||
prop = page.get("properties", {}).get(prop_name)
|
||||
if not prop:
|
||||
return None
|
||||
|
||||
if prop_type == "rich_text" and prop.get("type") == "rich_text":
|
||||
if prop.get("type") == "rich_text":
|
||||
text_parts = prop.get("rich_text", [])
|
||||
if text_parts:
|
||||
return text_parts[0].get("plain_text")
|
||||
|
||||
# Hier könnten weitere Typen wie 'select', 'number' etc. behandelt werden
|
||||
return None
|
||||
|
||||
def get_page_number_property(page: Dict, prop_name: str) -> Optional[float]:
|
||||
"""Extrahiert den Inhalt einer Number-Eigenschaft von einer Seite."""
|
||||
prop = page.get("properties", {}).get(prop_name)
|
||||
if not prop:
|
||||
return None
|
||||
|
||||
if prop.get("type") == "number":
|
||||
return prop.get("number")
|
||||
|
||||
return None
|
||||
|
||||
def get_page_date_property(page: Dict, prop_name: str) -> Optional[datetime]:
|
||||
"""Extrahiert den Inhalt einer Date-Eigenschaft von einer Seite."""
|
||||
prop = page.get("properties", {}).get(prop_name)
|
||||
if not prop:
|
||||
return None
|
||||
|
||||
if prop.get("type") == "date":
|
||||
date_info = prop.get("date")
|
||||
if date_info and date_info.get("start"):
|
||||
try:
|
||||
# Notion gibt Datumszeiten im ISO 8601 Format zurück (z.B. '2023-10-27T10:00:00.000+00:00')
|
||||
# oder nur Datum (z.B. '2023-10-27')
|
||||
# datetime.fromisoformat kann beides verarbeiten, aber Zeitzonen können komplex sein.
|
||||
# Für unsere Zwecke reicht es, wenn es als UTC betrachtet wird und wir die Dauer berechnen.
|
||||
return datetime.fromisoformat(date_info["start"].replace('Z', '+00:00'))
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
return None
|
||||
|
||||
def get_page_content(token: str, page_id: str) -> str:
|
||||
@@ -193,32 +227,42 @@ def get_database_status_options(token: str, db_id: str) -> List[str]:
|
||||
print(f"Fehler beim Abrufen der Datenbank-Eigenschaften: {e}")
|
||||
return []
|
||||
|
||||
def update_notion_task_status(token: str, task_id: str, status_value: str = "Doing") -> bool:
|
||||
"""Aktualisiert den Status eines Notion-Tasks."""
|
||||
print(f"\n--- Aktualisiere Status von Task '{task_id}' auf '{status_value}'... ---")
|
||||
def update_notion_task_property(token: str, task_id: str, prop_name: str, prop_value: Any, prop_type: str) -> bool:
|
||||
"""Aktualisiert eine bestimmte Eigenschaft (Property) eines Notion-Tasks."""
|
||||
print(f"\n--- Aktualisiere Task '{task_id}', Eigenschaft '{prop_name}' ({prop_type}) mit Wert '{prop_value}'... ---")
|
||||
url = f"https://api.notion.com/v1/pages/{task_id}"
|
||||
headers = {
|
||||
"Authorization": f"Bearer {token}",
|
||||
"Content-Type": "application/json",
|
||||
"Notion-Version": "2022-06-28"
|
||||
}
|
||||
payload = {
|
||||
"properties": {
|
||||
"Status": {
|
||||
"status": {
|
||||
"name": status_value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
payload_properties = {}
|
||||
if prop_type == "status":
|
||||
payload_properties[prop_name] = {"status": {"name": prop_value}}
|
||||
elif prop_type == "number":
|
||||
payload_properties[prop_name] = {"number": prop_value}
|
||||
elif prop_type == "date":
|
||||
# Notion erwartet Datum im ISO 8601 Format
|
||||
if isinstance(prop_value, datetime):
|
||||
payload_properties[prop_name] = {"date": {"start": prop_value.isoformat()}}
|
||||
else:
|
||||
print(f"❌ FEHLER: Ungültiges Datumformat für '{prop_name}'. Erwartet datetime-Objekt.")
|
||||
return False
|
||||
# Weitere Typen können hier hinzugefügt werden (z.B. rich_text, multi_select etc.)
|
||||
else:
|
||||
print(f"❌ FEHLER: Nicht unterstützter Eigenschaftstyp '{prop_type}' für Update.")
|
||||
return False
|
||||
|
||||
payload = {"properties": payload_properties}
|
||||
|
||||
try:
|
||||
response = requests.patch(url, headers=headers, json=payload)
|
||||
response.raise_for_status()
|
||||
print(f"✅ Task-Status erfolgreich auf '{status_value}' aktualisiert.")
|
||||
print(f"✅ Task-Eigenschaft '{prop_name}' erfolgreich aktualisiert.")
|
||||
return True
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"❌ FEHLER beim Aktualisieren des Task-Status: {e}")
|
||||
print(f"❌ FEHLER beim Aktualisieren der Task-Eigenschaft '{prop_name}': {e}")
|
||||
try:
|
||||
print(f"Antwort des Servers: {json.dumps(e.response.json(), indent=2)}")
|
||||
except:
|
||||
@@ -395,7 +439,7 @@ def select_project(token: str) -> Optional[Tuple[Dict, Optional[str]]]:
|
||||
choice = int(input("Bitte wähle eine Nummer: "))
|
||||
if 1 <= choice <= len(projects):
|
||||
selected_project = projects[choice - 1]
|
||||
readme_path = get_page_property(selected_project, "Readme Path")
|
||||
readme_path = get_page_rich_text_property(selected_project, "Readme Path")
|
||||
return selected_project, readme_path
|
||||
else:
|
||||
print("Ungültige Auswahl.")
|
||||
@@ -491,13 +535,68 @@ def report_status_to_notion(
|
||||
session_data = json.load(f)
|
||||
task_id = session_data.get("task_id")
|
||||
token = session_data.get("token")
|
||||
session_start_time_str = session_data.get("session_start_time")
|
||||
|
||||
if not (task_id and token):
|
||||
print("❌ FEHLER: Session-Daten unvollständig. Kann keinen Statusbericht erstellen.")
|
||||
if not (task_id and token and session_start_time_str):
|
||||
print("❌ FEHLER: Session-Daten unvollständig oder Startzeit fehlt. Kann keinen Statusbericht erstellen.")
|
||||
return
|
||||
|
||||
try:
|
||||
session_start_time = datetime.fromisoformat(session_start_time_str)
|
||||
except ValueError:
|
||||
print(f"❌ FEHLER: Ungültiges Startzeitformat in Session-Daten: {session_start_time_str}")
|
||||
return
|
||||
|
||||
print(f"--- Erstelle Statusbericht für Task {task_id} ---")
|
||||
|
||||
tasks_db_id = find_database_by_title(token, "Tasks [UT]")
|
||||
if not tasks_db_id:
|
||||
return
|
||||
|
||||
# 1. Aktuelles Task-Objekt abrufen, um die vorhandene Dauer zu lesen
|
||||
page_url = f"https://api.notion.com/v1/pages/{task_id}"
|
||||
headers = {
|
||||
"Authorization": f"Bearer {token}",
|
||||
"Content-Type": "application/json",
|
||||
"Notion-Version": "2022-06-28"
|
||||
}
|
||||
current_task_page = None
|
||||
try:
|
||||
response = requests.get(page_url, headers=headers)
|
||||
response.raise_for_status()
|
||||
current_task_page = response.json()
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"❌ FEHLER beim Abrufen der Task-Seite {task_id}: {e}")
|
||||
return
|
||||
|
||||
if not current_task_page:
|
||||
print(f"❌ FEHLER: Konnte den Task {task_id} in Notion nicht finden. Zeiterfassung wird übersprungen.")
|
||||
return
|
||||
|
||||
# 2. Bestehende Total Duration (h) abrufen
|
||||
existing_duration = get_page_number_property(current_task_page, "Total Duration (h)")
|
||||
if existing_duration is None:
|
||||
existing_duration = 0.0
|
||||
|
||||
# 3. Dauer der aktuellen Arbeitseinheit berechnen
|
||||
current_end_time = datetime.now()
|
||||
time_spent = (current_end_time - session_start_time).total_seconds() / 3600.0 # Dauer in Stunden
|
||||
|
||||
# 4. Neue Gesamtdauer berechnen
|
||||
new_total_duration = existing_duration + time_spent
|
||||
|
||||
# 5. Total Duration (h) in Notion aktualisieren
|
||||
update_notion_task_property(token, task_id, "Total Duration (h)", round(new_total_duration, 2), "number")
|
||||
|
||||
# 6. session_start_time in SESSION_INFO für die nächste Arbeitseinheit aktualisieren
|
||||
# Hier speichern wir die Endzeit als neue Startzeit für die nächste mögliche Einheit
|
||||
# oder löschen sie, wenn die Session als beendet betrachtet wird.
|
||||
# Entsprechend des Plans setzen wir sie zurück (auf die aktuelle Endzeit der Arbeitseinheit).
|
||||
session_data["session_start_time"] = current_end_time.isoformat()
|
||||
with open(SESSION_FILE_PATH, "w") as f:
|
||||
json.dump(session_data, f)
|
||||
|
||||
|
||||
# Git-Zusammenfassung generieren (immer, wenn nicht explizit überschrieben)
|
||||
actual_git_changes = git_changes_override
|
||||
actual_commit_messages = commit_messages_override
|
||||
@@ -601,7 +700,7 @@ def report_status_to_notion(
|
||||
|
||||
# Notion aktualisieren
|
||||
append_blocks_to_notion_page(token, task_id, notion_blocks)
|
||||
update_notion_task_status(token, task_id, actual_status)
|
||||
update_notion_task_property(token, task_id, "Status", actual_status, "status")
|
||||
|
||||
except (FileNotFoundError, json.JSONDecodeError) as e:
|
||||
print(f"❌ FEHLER beim Lesen der Session-Informationen für Statusbericht: {e}")
|
||||
@@ -641,20 +740,13 @@ def generate_cli_context(project_title: str, task_title: str, task_id: str, read
|
||||
|
||||
# Die start_gemini_cli Funktion wird entfernt, da das aufrufende Skript jetzt die Gemini CLI startet.
|
||||
|
||||
import shutil
|
||||
import argparse
|
||||
|
||||
# --- Session Management ---
|
||||
|
||||
SESSION_DIR = ".dev_session"
|
||||
SESSION_FILE_PATH = os.path.join(SESSION_DIR, "SESSION_INFO")
|
||||
|
||||
def save_session_info(task_id: str, token: str):
|
||||
"""Speichert die Task-ID und den Token für den Git-Hook."""
|
||||
def save_session_info(task_id: str, token: str, session_start_time: datetime):
|
||||
"""Speichert die Task-ID, den Token und die Startzeit der Session."""
|
||||
os.makedirs(SESSION_DIR, exist_ok=True)
|
||||
session_data = {
|
||||
"task_id": task_id,
|
||||
"token": token
|
||||
"token": token,
|
||||
"session_start_time": session_start_time.isoformat() # Speichern als ISO-Format String
|
||||
}
|
||||
with open(SESSION_FILE_PATH, "w") as f:
|
||||
json.dump(session_data, f)
|
||||
@@ -713,7 +805,7 @@ def complete_session():
|
||||
status_options = get_database_status_options(token, tasks_db_id)
|
||||
if status_options:
|
||||
done_status = status_options[-1]
|
||||
update_notion_task_status(token, task_id, done_status)
|
||||
update_notion_task_property(token, task_id, "Status", done_status, "status")
|
||||
|
||||
except (FileNotFoundError, json.JSONDecodeError):
|
||||
print("Fehler beim Lesen der Session-Informationen.")
|
||||
@@ -771,7 +863,7 @@ def start_interactive_session():
|
||||
task_description = get_page_content(token, task_id)
|
||||
|
||||
# Session-Informationen für den Git-Hook speichern
|
||||
save_session_info(task_id, token)
|
||||
save_session_info(task_id, token, datetime.now())
|
||||
|
||||
# Git-Hook installieren, der die Session-Infos nutzt
|
||||
install_git_hook()
|
||||
@@ -782,7 +874,7 @@ def start_interactive_session():
|
||||
|
||||
suggested_branch_name = f"feature/task-{task_id.split('-')[0]}-{title_slug}"
|
||||
|
||||
status_updated = update_notion_task_status(token, task_id, "Doing")
|
||||
status_updated = update_notion_task_property(token, task_id, "Status", "Doing", "status")
|
||||
if not status_updated:
|
||||
print("Warnung: Notion-Task-Status konnte nicht aktualisiert werden.")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user