feat(projects): Threads im Hauptchat verankert (Stefan-Konzept)

Projekte sind benannte Thema-Bündel die voice-gesteuert via Brain-Tools
geöffnet/verlassen werden. Default-Mode bleibt der Hauptthread — Projekte
sind eine optionale Bühne. Anchored-not-replaced: App-Open landet immer
im Hauptchat, Projekte sind nur sichtbar wenn aktiv betreten.

Brain:
- projects.py: CRUD + Fuzzy-Find + Active-State-Pointer
  (/shared/config/projects.json + active_project.txt).
- conversation.py: Turn.project_id-Feld + window(project_id) Filter.
- agent.py: 6 Meta-Tools — project_create / _enter / _exit / _list /
  _summary / _end. chat() liest aktive Projekt-ID, taggt User+Assistant-
  Turns damit, filtert das LLM-Window auf Projekt-Kontext und ergaenzt
  den System-Prompt um den aktiven Projekt-Hinweis. touch_project pflegt
  last_activity_at + turn_count.
- main.py: REST-Endpoints /projects/{status,list,create,switch,
  {id}/end,{id}/archive, PATCH /{id}}.

Bridge + RVS:
- aria_bridge.py: project_changed Event-Propagation Brain → RVS-Broadcast
  damit App + Diagnostic ihre Banner refreshen.
- rvs/server.js: project_changed in ALLOWED_TYPES.

App:
- brainApi.ts: Project-Type + 6 API-Methoden.
- ProjectsBrowser.tsx (neue Komponente, ~340 Zeilen): Status-Header,
  Hauptchat als Erster-Eintrag, Projekt-Liste mit Aktiv-Marker, Long-Press
  zum Editieren, Modals fuer Neu/Edit/End/Archiv.
- ChatScreen.tsx: Banner unterhalb des Status-Bars zeigt aktives Projekt
  oder „Hauptchat" — Tap öffnet ProjectsBrowser als Modal. Aktive Projekt-
  Info wird bei Mount + bei project_changed-Events refreshed.
- SettingsScreen.tsx: Neue Section 📁 „Projekte" zeigt ProjectsBrowser inline.

Diagnostic:
- Neue Sektion im Brain-Tab mit Liste, Aktiv-Marker, Beenden/Archivieren
  pro Zeile, Modal fuer Neu. Lädt automatisch bei Brain-Tab + bei
  project_changed-Event-Broadcast.

Was bewusst NICHT drin ist (Folgeschritte):
- Per-Message Filter im Chat-Verlauf (zeigt aktuell alle Bubbles, Banner
  zeigt Kontext) — App müsste Chat-History per project_id filtern.
- Files-by-Project Tagging.
- Inline-Collapse-Bloecke im Chat-Verlauf.
- Sub-Projekte (Stefan-Entscheidung: weglassen, „Mama-tauglich").

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-06-13 13:51:26 +02:00
parent f714cfc336
commit fc0f91d1e6
11 changed files with 1239 additions and 19 deletions
+14
View File
@@ -1564,6 +1564,20 @@ class ARIABridge:
logger.info("[brain] ARIA hat eine Memory angelegt: %s (type=%s)",
event.get("memory", {}).get("title"),
event.get("memory", {}).get("type"))
elif etype == "project_changed":
# ARIA hat ein Projekt erstellt / betreten / verlassen / beendet.
# App + Diagnostic refreshen ihren Projekt-Banner anhand des Events.
await self._send_to_rvs({
"type": "project_changed",
"payload": {
"action": event.get("action") or "",
**(event.get("project") or {}),
},
"timestamp": int(asyncio.get_event_loop().time() * 1000),
})
proj = event.get("project") or {}
logger.info("[brain] Projekt %s: %s (id=%s)",
event.get("action") or "?", proj.get("name"), proj.get("id"))
# _process_core_response uebernimmt alles weitere:
# File-Marker extrahieren + broadcasten, NO_REPLY-Check, Chat-