Assistent: Layout-Fix, Auth-Fix, Session-Reaktivierung

- CSS: Feste Hoehe, overflow hidden, Input-Bar immer sichtbar
- Auth: Prueft username UND displayName gegen E-Mail und Name
- Beendete Sessions werden automatisch reaktiviert beim Senden

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Dieser Commit ist enthalten in:
Server Deploy
2026-03-19 23:16:17 +01:00
Ursprung ecd8158532
Commit 4040b5f306
3 geänderte Dateien mit 83 neuen und 26 gelöschten Zeilen

Datei anzeigen

@@ -94,10 +94,12 @@ class AssistantManager {
this.setStatus(data.status);
// If session ended, finalize streaming
if (data.status === 'ended' || data.status === 'stopped') {
// Finalize streaming when message processing completes
if (data.status === 'ended' || data.status === 'stopped' || data.status === 'active') {
this.finalizeStreaming();
this.loadSessions();
if (data.status !== 'active') {
this.loadSessions();
}
}
});
}
@@ -178,7 +180,16 @@ class AssistantManager {
if (session) {
this.chatTitleEl.textContent = session.title;
this.setStatus(session.status === 'active' ? 'ended' : session.status);
if (session.status === 'active') {
// Aktive Session mit Backend verbinden
const socket = syncManager.socket;
if (socket) {
socket.emit('assistant:start', { sessionId: id });
}
} else {
this.setStatus(session.status);
}
}
this.renderSessionsList();
@@ -211,7 +222,7 @@ class AssistantManager {
this.currentSessionId = session.id;
this.chatTitleEl.textContent = session.title;
this.messagesEl.innerHTML = '';
this.setStatus('running');
this.setStatus('active');
this.updateChatState();
// Start Claude process via Socket
@@ -261,10 +272,22 @@ class AssistantManager {
// MESSAGING
// =====================
sendMessage() {
async sendMessage() {
const text = this.inputEl?.value?.trim();
if (!text || !this.currentSessionId) return;
// Beendete/gestoppte Session zuerst reaktivieren
if (this.sessionStatus === 'ended' || this.sessionStatus === 'stopped') {
try {
await this._reactivateSession();
this.loadSessions();
} catch (err) {
console.error('[Assistant] Reaktivierung fehlgeschlagen:', err);
this.showToast('Session konnte nicht reaktiviert werden', 'error');
return;
}
}
// Render user message
this.renderMessage('user', text);
this.inputEl.value = '';
@@ -285,6 +308,32 @@ class AssistantManager {
this.setStatus('thinking');
}
_reactivateSession() {
return new Promise((resolve, reject) => {
const socket = syncManager.socket;
if (!socket) return reject(new Error('Kein Socket'));
const onStatus = (data) => {
if (data.sessionId !== this.currentSessionId) return;
socket.off('assistant:status', onStatus);
clearTimeout(timeout);
if (data.status === 'error') {
reject(new Error(data.error || 'Fehler'));
} else {
resolve();
}
};
const timeout = setTimeout(() => {
socket.off('assistant:status', onStatus);
reject(new Error('Timeout'));
}, 10000);
socket.on('assistant:status', onStatus);
socket.emit('assistant:start', { sessionId: this.currentSessionId });
});
}
handleOutput(content) {
if (!this.streamingMessageEl) {
// Create streaming bubble if not exists
@@ -401,6 +450,7 @@ class AssistantManager {
}
const labels = {
active: 'Bereit',
running: 'Aktiv',
thinking: 'Denkt...',
ended: 'Beendet',