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:
@@ -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',
|
||||
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren