`;
}
- function ariaPanicStop() {
- if (!confirm('Wirklich NOT-AUS? Alle aktiven Claude-Subprocesses werden sofort gekillt.')) return;
+ async function ariaPanicStop() {
+ if (!await uiConfirm('Wirklich NOT-AUS? Alle aktiven Claude-Subprocesses werden sofort gekillt.')) return;
send({ action: 'aria_panic_stop' });
_ariaPushLine(
`━━━ ${_ariaTimePrefix()} ⛔ NOT-AUS ausgeloest ━━━`,
@@ -5679,8 +5743,8 @@
}
/** Entfernt einen Agenten aus der Liste (z.B. den alten Namen nach dem
* Umbenennen). Läuft er noch, meldet er sich von selbst wieder. */
- function forgetHost(hostId, name) {
- if (!confirm('"' + name + '" aus der Liste entfernen?\n\n' +
+ async function forgetHost(hostId, name) {
+ if (!await uiConfirm('"' + name + '" aus der Liste entfernen?\n\n' +
'Das stoppt den Agenten NICHT — läuft er noch, erscheint er ' +
'beim nächsten Lebenszeichen wieder.')) return;
send({ action: 'host_forget', hostId });
@@ -5756,7 +5820,7 @@
if (pw) body.password = pw;
if (spw) body.smtp_password = spw;
if (body.imap_encryption === 'none' || body.smtp_encryption === 'none') {
- if (!confirm('Ohne Verschlüsselung gehen Passwort und Mails im Klartext durchs Netz. Trotzdem speichern?')) return;
+ if (!await uiConfirm('Ohne Verschlüsselung gehen Passwort und Mails im Klartext durchs Netz. Trotzdem speichern?')) return;
}
_mailStatus('Speichere …');
try {
@@ -5809,9 +5873,9 @@
renderJellyfin();
}
- function removeJellyfinServer(i) {
+ async function removeJellyfinServer(i) {
const s = jellyfinServers[i];
- if (!confirm('Server "' + (s.name || s.url || 'neu') + '" entfernen?')) return;
+ if (!await uiConfirm('Server "' + (s.name || s.url || 'neu') + '" entfernen?')) return;
jellyfinServers.splice(i, 1);
if (jellyfinServers.length && !jellyfinServers.some(x => x.isDefault)) {
jellyfinServers[0].isDefault = true;
@@ -6110,9 +6174,9 @@
* sofort und fuer jeden schon ausgerollten Agenten. Die Bridge loest ihn
* beim Ansprechen wieder auf, damit sich der Agent weiter angesprochen
* fuehlt. */
- function renameEntity(kind, id, currentAlias, ownName) {
+ async function renameEntity(kind, id, currentAlias, ownName) {
const was = kind === 'satellite' ? 'Satellit' : 'Agent';
- const name = prompt(
+ const name = await uiPrompt(
was + ' umbenennen\n\n'
+ 'Heißt sich selbst: ' + ownName + '\n'
+ 'ARIA spricht ihn danach unter dem neuen Namen an.\n'
@@ -6126,8 +6190,8 @@
* ("mach mir Port 5000 von duffy-desktop auf") statt ueber eine IP.
* Gespeichert wird an der MAC — ein IP-Wechsel per DHCP verliert den
* Namen dann nicht. */
- function renameSatDevice(satId, mac, ip, current) {
- const name = prompt(
+ async function renameSatDevice(satId, mac, ip, current) {
+ const name = await uiPrompt(
'Name für ' + (ip || mac) + '\n\n'
+ 'ARIA spricht das Gerät danach so an. Leer lassen = Namen entfernen.',
current || '');
@@ -6354,17 +6418,17 @@
});
loadTriggers();
} catch (e) {
- alert('Toggle fehlgeschlagen: ' + e.message);
+ uiAlert('Toggle fehlgeschlagen: ' + e.message);
}
}
async function deleteTrigger(name) {
- if (!confirm(`Trigger "${name}" wirklich löschen?`)) return;
+ if (!await uiConfirm(`Trigger "${name}" wirklich löschen?`)) return;
try {
await fetch('/api/brain/triggers/' + encodeURIComponent(name), { method: 'DELETE' });
loadTriggers();
} catch (e) {
- alert('Löschen fehlgeschlagen: ' + e.message);
+ uiAlert('Löschen fehlgeschlagen: ' + e.message);
}
}
@@ -6423,7 +6487,7 @@
/** Edit-Modus: Modal mit existierenden Trigger-Werten fuellen. */
async function openTriggerEdit(name) {
const t = triggersCache.find(x => x.name === name);
- if (!t) { alert('Trigger nicht in cache, lade neu...'); loadTriggers(); return; }
+ if (!t) { uiAlert('Trigger nicht in cache, lade neu...'); loadTriggers(); return; }
editingTriggerName = name;
document.getElementById('trigger-modal-title').textContent = 'Trigger bearbeiten — ' + name;
document.getElementById('trigger-modal-save-btn').textContent = 'Speichern';
@@ -6725,7 +6789,7 @@
if (stat) { stat.textContent = 'Fehler ' + r.status; stat.style.color = '#FF6B6B'; }
}
} catch (e) {
- alert('Speichern fehlgeschlagen: ' + e.message);
+ uiAlert('Speichern fehlgeschlagen: ' + e.message);
}
}
@@ -6760,7 +6824,7 @@
}
async function rollbackSkillVersion(name, versionId) {
- if (!confirm(`Skill "${name}" auf Version ${versionId} zurückrollen?\n\nDer aktuelle Stand wird vorher automatisch gesichert (safety-snapshot).`)) return;
+ if (!await uiConfirm(`Skill "${name}" auf Version ${versionId} zurückrollen?\n\nDer aktuelle Stand wird vorher automatisch gesichert (safety-snapshot).`)) return;
try {
const r = await fetch('/api/brain/skills/' + encodeURIComponent(name) + '/rollback', {
method: 'POST', headers: {'Content-Type':'application/json'},
@@ -6768,24 +6832,24 @@
});
const d = await r.json();
if (r.ok) {
- alert(`✓ Rollback OK\nSicherheits-Snapshot: ${d.safety_snapshot}`);
+ uiAlert(`✓ Rollback OK\nSicherheits-Snapshot: ${d.safety_snapshot}`);
loadSkillVersionsSection(name);
loadSkills();
} else {
- alert('Rollback fehlgeschlagen: ' + (d.detail || JSON.stringify(d)));
+ uiAlert('Rollback fehlgeschlagen: ' + (d.detail || JSON.stringify(d)));
}
- } catch (e) { alert('Rollback-Fehler: ' + e.message); }
+ } catch (e) { uiAlert('Rollback-Fehler: ' + e.message); }
}
async function deleteSkillVersion(name, versionId) {
- if (!confirm(`Version ${versionId} von "${name}" wirklich löschen?\n\nNicht rückholbar.`)) return;
+ if (!await uiConfirm(`Version ${versionId} von "${name}" wirklich löschen?\n\nNicht rückholbar.`)) return;
try {
const r = await fetch('/api/brain/skills/' + encodeURIComponent(name) + '/versions/' + encodeURIComponent(versionId), {
method: 'DELETE',
});
if (r.ok) loadSkillVersionsSection(name);
- else { const d = await r.json().catch(()=>({})); alert('Löschen fehlgeschlagen: ' + (d.detail || r.status)); }
- } catch (e) { alert('Fehler: ' + e.message); }
+ else { const d = await r.json().catch(()=>({})); uiAlert('Löschen fehlgeschlagen: ' + (d.detail || r.status)); }
+ } catch (e) { uiAlert('Fehler: ' + e.message); }
}
async function toggleSkillActive(name, newActive) {
@@ -6797,29 +6861,29 @@
});
loadSkills();
} catch (e) {
- alert('Toggle fehlgeschlagen: ' + e.message);
+ uiAlert('Toggle fehlgeschlagen: ' + e.message);
}
}
async function deleteSkill(name) {
- if (!confirm(`Skill "${name}" wirklich löschen?\n\nFolder, venv, Logs — alles weg.`)) return;
+ if (!await uiConfirm(`Skill "${name}" wirklich löschen?\n\nFolder, venv, Logs — alles weg.`)) return;
try {
await fetch('/api/brain/skills/' + encodeURIComponent(name), { method: 'DELETE' });
skillExpanded.delete(name);
loadSkills();
} catch (e) {
- alert('Löschen fehlgeschlagen: ' + e.message);
+ uiAlert('Löschen fehlgeschlagen: ' + e.message);
}
}
async function runSkillPrompt(name) {
- const argsStr = prompt(`Skill "${name}" ausführen.\n\nArgs als JSON (oder leer):`, '{}');
+ const argsStr = await uiPrompt(`Skill "${name}" ausführen.\n\nArgs als JSON (oder leer):`, '{}');
if (argsStr === null) return;
let args = {};
try {
args = JSON.parse(argsStr || '{}');
} catch (e) {
- alert('Ungültiges JSON: ' + e.message);
+ uiAlert('Ungültiges JSON: ' + e.message);
return;
}
try {
@@ -6830,11 +6894,11 @@
});
const d = await r.json();
const summary = `${d.ok ? '✓ OK' : '✗ FEHLER'} · ${d.duration_sec}s · exit=${d.exit_code}\n\nstdout:\n${(d.stdout||'').slice(0,1500)}\n\nstderr:\n${(d.stderr||'').slice(0,500)}`;
- alert(summary);
+ uiAlert(summary);
if (skillExpanded.has(name)) toggleSkillExpand(name); // refresh logs by collapse+expand
loadSkills();
} catch (e) {
- alert('Run fehlgeschlagen: ' + e.message);
+ uiAlert('Run fehlgeschlagen: ' + e.message);
}
}
@@ -6845,7 +6909,7 @@
async function importSkillFile(event) {
const file = event.target.files[0];
if (!file) return;
- if (!confirm(`Skill aus "${file.name}" importieren?\n\nFalls schon vorhanden mit gleichem Namen, wird er überschrieben.`)) {
+ if (!await uiConfirm(`Skill aus "${file.name}" importieren?\n\nFalls schon vorhanden mit gleichem Namen, wird er überschrieben.`)) {
event.target.value = ''; return;
}
try {
@@ -6856,13 +6920,13 @@
});
const d = await r.json();
if (r.ok) {
- alert(`✓ Skill "${d.imported?.name}" importiert.`);
+ uiAlert(`✓ Skill "${d.imported?.name}" importiert.`);
loadSkills();
} else {
- alert('Import fehlgeschlagen: ' + (d.detail || JSON.stringify(d)));
+ uiAlert('Import fehlgeschlagen: ' + (d.detail || JSON.stringify(d)));
}
} catch (e) {
- alert('Import fehlgeschlagen: ' + e.message);
+ uiAlert('Import fehlgeschlagen: ' + e.message);
} finally {
event.target.value = '';
}
@@ -7027,7 +7091,7 @@
if (f) f.projectId = projectId || '';
renderFilesList();
} catch (e) {
- alert('Zuordnung fehlgeschlagen: ' + e.message);
+ uiAlert('Zuordnung fehlgeschlagen: ' + e.message);
renderFilesList(); // Dropdown auf alten Wert zuruecksetzen
}
}
@@ -7086,7 +7150,7 @@
}
async function restoreVersion(rel, hash) {
- if (!confirm(`Diese Version (${hash.slice(0,7)}) als aktive Version setzen?\n\nDie aktuelle Version bleibt rollback-bar in der Historie.`)) return;
+ if (!await uiConfirm(`Diese Version (${hash.slice(0,7)}) als aktive Version setzen?\n\nDie aktuelle Version bleibt rollback-bar in der Historie.`)) return;
try {
const r = await fetch('/api/files-version-restore', {
method: 'POST',
@@ -7099,7 +7163,7 @@
showVersions(rel);
loadFiles();
} catch (e) {
- alert('Restore fehlgeschlagen: ' + e.message);
+ uiAlert('Restore fehlgeschlagen: ' + e.message);
}
}
@@ -7131,14 +7195,14 @@
document.body.appendChild(a); a.click();
setTimeout(() => { URL.revokeObjectURL(url); a.remove(); }, 100);
} catch (e) {
- alert('ZIP-Download fehlgeschlagen: ' + e.message);
+ uiAlert('ZIP-Download fehlgeschlagen: ' + e.message);
}
}
async function deleteSelected() {
const paths = [...filesSelected];
if (!paths.length) return;
- if (!confirm(`${paths.length} Datei(en) wirklich löschen?\n\nIn allen Chat-Bubbles werden sie als gelöscht markiert.`)) return;
+ if (!await uiConfirm(`${paths.length} Datei(en) wirklich löschen?\n\nIn allen Chat-Bubbles werden sie als gelöscht markiert.`)) return;
try {
const r = await fetch('/api/files-delete-batch', {
method: 'POST',
@@ -7150,10 +7214,10 @@
filesSelected.clear();
loadFiles();
} else {
- alert('Bulk-Delete fehlgeschlagen: ' + (d.error || 'unbekannt'));
+ uiAlert('Bulk-Delete fehlgeschlagen: ' + (d.error || 'unbekannt'));
}
} catch (e) {
- alert('Bulk-Delete fehlgeschlagen: ' + e.message);
+ uiAlert('Bulk-Delete fehlgeschlagen: ' + e.message);
}
}
@@ -7168,7 +7232,7 @@
}
async function deleteFile(p, name) {
- if (!confirm(`Datei "${name}" wirklich löschen?\n\nIn allen Chat-Bubbles wird sie als gelöscht markiert.`)) return;
+ if (!await uiConfirm(`Datei "${name}" wirklich löschen?\n\nIn allen Chat-Bubbles wird sie als gelöscht markiert.`)) return;
try {
const r = await fetch('/api/files-delete', {
method: 'POST',
@@ -7180,10 +7244,10 @@
loadFiles();
// Server broadcastet file_deleted Event → markFileDeletedInChat() updated bubbles
} else {
- alert('Löschen fehlgeschlagen: ' + d.error);
+ uiAlert('Löschen fehlgeschlagen: ' + d.error);
}
} catch (e) {
- alert('Löschen fehlgeschlagen: ' + e.message);
+ uiAlert('Löschen fehlgeschlagen: ' + e.message);
}
}
@@ -7354,17 +7418,17 @@
listEl.innerHTML = `
Fehler beim Laden: ${_ofmt(e.message)}
`;
}
}
- function openOAuthCustomDialog() {
- const name = (prompt('Service-Name (z.B. dropbox, discord) — a-z 0-9 _ -:') || '').trim().toLowerCase();
+ async function openOAuthCustomDialog() {
+ const name = (await uiPrompt('Service-Name (z.B. dropbox, discord) — a-z 0-9 _ -:') || '').trim().toLowerCase();
if (!name || !/^[a-z0-9_-]+$/.test(name)) {
- if (name) alert('Ungueltiger Name. Erlaubt: a-z 0-9 _ -');
+ if (name) uiAlert('Ungueltiger Name. Erlaubt: a-z 0-9 _ -');
return;
}
- const authUrl = (prompt(`auth_url fuer ${name}:`, 'https://') || '').trim();
+ const authUrl = (await uiPrompt(`auth_url fuer ${name}:`, 'https://') || '').trim();
if (!authUrl) return;
- const tokenUrl = (prompt(`token_url fuer ${name}:`, 'https://') || '').trim();
+ const tokenUrl = (await uiPrompt(`token_url fuer ${name}:`, 'https://') || '').trim();
if (!tokenUrl) return;
- const scopesRaw = (prompt(`scopes (space-separated, optional):`, '') || '').trim();
+ const scopesRaw = (await uiPrompt(`scopes (space-separated, optional):`, '') || '').trim();
const scopes = scopesRaw ? scopesRaw.split(/\s+/).filter(Boolean) : undefined;
fetch('/api/brain/oauth/apps', {
method: 'POST',
@@ -7373,19 +7437,19 @@
})
.then(r => r.ok ? r.json() : r.text().then(t => Promise.reject(new Error(t))))
.then(() => loadOAuthServices())
- .catch(e => alert('Custom-Service anlegen fehlgeschlagen: ' + e.message));
+ .catch(e => uiAlert('Custom-Service anlegen fehlgeschlagen: ' + e.message));
}
async function deleteOAuthApp(service) {
- if (!confirm(`Service "${service}" komplett entfernen? client_id/secret + Token werden geloescht.`)) return;
+ if (!await uiConfirm(`Service "${service}" komplett entfernen? client_id/secret + Token werden geloescht.`)) return;
try {
const r = await fetch('/api/brain/oauth/apps/' + encodeURIComponent(service), { method: 'DELETE' });
if (!r.ok) {
- alert('Loeschen fehlgeschlagen: ' + (await r.text()));
+ uiAlert('Loeschen fehlgeschlagen: ' + (await r.text()));
return;
}
loadOAuthServices();
} catch (e) {
- alert('Loeschen fehlgeschlagen: ' + e.message);
+ uiAlert('Loeschen fehlgeschlagen: ' + e.message);
}
}
async function saveOAuthApp(service) {
@@ -7395,7 +7459,7 @@
const tokenUrl = (document.getElementById('oauth-tok-' + service)?.value || '').trim();
const scopesRaw = (document.getElementById('oauth-scopes-' + service)?.value || '').trim();
if (!cid) {
- alert('client_id darf nicht leer sein.');
+ uiAlert('client_id darf nicht leer sein.');
return;
}
const body = { service, client_id: cid, client_secret: sec };
@@ -7410,12 +7474,12 @@
});
if (!r.ok) {
const t = await r.text();
- alert('Speichern fehlgeschlagen: ' + t);
+ uiAlert('Speichern fehlgeschlagen: ' + t);
return;
}
loadOAuthServices();
} catch (e) {
- alert('Speichern fehlgeschlagen: ' + e.message);
+ uiAlert('Speichern fehlgeschlagen: ' + e.message);
}
}
async function authorizeOAuth(service) {
@@ -7427,7 +7491,7 @@
});
if (!r.ok) {
const t = await r.text();
- alert('Authorize fehlgeschlagen: ' + t);
+ uiAlert('Authorize fehlgeschlagen: ' + t);
return;
}
const data = await r.json();
@@ -7436,39 +7500,39 @@
// Status nach ein paar Sekunden refreshen — Provider redirect → RVS → Brain
setTimeout(loadOAuthServices, 8000);
} catch (e) {
- alert('Authorize fehlgeschlagen: ' + e.message);
+ uiAlert('Authorize fehlgeschlagen: ' + e.message);
}
}
async function revokeOAuth(service) {
- if (!confirm(`Token fuer ${service} wirklich loeschen? ARIA muss danach neu autorisiert werden.`)) return;
+ if (!await uiConfirm(`Token fuer ${service} wirklich loeschen? ARIA muss danach neu autorisiert werden.`)) return;
try {
const r = await fetch('/api/brain/oauth/' + service + '/revoke', { method: 'POST' });
if (!r.ok) {
const t = await r.text();
- alert('Revoke fehlgeschlagen: ' + t);
+ uiAlert('Revoke fehlgeschlagen: ' + t);
return;
}
loadOAuthServices();
} catch (e) {
- alert('Revoke fehlgeschlagen: ' + e.message);
+ uiAlert('Revoke fehlgeschlagen: ' + e.message);
}
}
async function distillNow() {
- if (!confirm('Destillat manuell auslösen?\n\nDie ältesten Turns werden zu fact-Memories verdichtet — kostet einen Claude-Call.')) return;
+ if (!await uiConfirm('Destillat manuell auslösen?\n\nDie ältesten Turns werden zu fact-Memories verdichtet — kostet einen Claude-Call.')) return;
try {
const r = await fetch('/api/brain/conversation/distill', { method: 'POST' });
const d = await r.json();
- alert(`Destillat: ${d.distilled || 0} Facts geschrieben, ${d.removed_turns || 0} Turns entfernt.${d.error ? '\nFehler: ' + d.error : ''}`);
+ uiAlert(`Destillat: ${d.distilled || 0} Facts geschrieben, ${d.removed_turns || 0} Turns entfernt.${d.error ? '\nFehler: ' + d.error : ''}`);
loadBrainStatus();
loadBrainMemoryList();
} catch (e) {
- alert('Destillat fehlgeschlagen: ' + e.message);
+ uiAlert('Destillat fehlgeschlagen: ' + e.message);
}
}
async function resetConversation() {
- if (!confirm('Konversation komplett zurücksetzen?\n\n• ARIAs Rolling-Window (Brain) wird geleert — sie "vergisst" die letzten Turns\n• Chat-Anzeige in der Diagnostic wird geleert\n\nDestillierte Facts + andere Memories bleiben in der Vector-DB.')) return;
+ if (!await uiConfirm('Konversation komplett zurücksetzen?\n\n• ARIAs Rolling-Window (Brain) wird geleert — sie "vergisst" die letzten Turns\n• Chat-Anzeige in der Diagnostic wird geleert\n\nDestillierte Facts + andere Memories bleiben in der Vector-DB.')) return;
try {
// Beides parallel — Brain Window + Diagnostic chat_backup
const [brainR, histR] = await Promise.all([
@@ -7484,10 +7548,10 @@
if (fsBox) fsBox.innerHTML = '';
loadBrainStatus();
} else {
- alert(`Reset teilweise fehlgeschlagen — Brain: ${brainOk ? 'OK' : 'fail'}, History: ${histOk ? 'OK' : 'fail'}`);
+ uiAlert(`Reset teilweise fehlgeschlagen — Brain: ${brainOk ? 'OK' : 'fail'}, History: ${histOk ? 'OK' : 'fail'}`);
}
} catch (e) {
- alert('Reset fehlgeschlagen: ' + e.message);
+ uiAlert('Reset fehlgeschlagen: ' + e.message);
}
}
@@ -8142,14 +8206,14 @@
const win = window.open('', '_blank');
if (!win) {
- alert('Popup blockiert — bitte Popups für Diagnostic erlauben und nochmal klicken.');
+ uiAlert('Popup blockiert — bitte Popups für Diagnostic erlauben und nochmal klicken.');
return;
}
win.document.open();
win.document.write(html);
win.document.close();
} catch (e) {
- alert('Druckansicht konnte nicht geladen werden: ' + e.message);
+ uiAlert('Druckansicht konnte nicht geladen werden: ' + e.message);
}
}
@@ -8282,7 +8346,7 @@
const id = document.getElementById('memory-edit-id').value;
if (!id) return;
const name = decodeURIComponent(filenameEncoded);
- if (!confirm(`Anhang "${name}" wirklich loeschen?`)) return;
+ if (!await uiConfirm(`Anhang "${name}" wirklich loeschen?`)) return;
try {
const r = await fetch(`/api/brain/memory/${encodeURIComponent(id)}/attachments/${filenameEncoded}`, {
method: 'DELETE',
@@ -8294,7 +8358,7 @@
const status = document.getElementById('memory-attachment-status');
if (status) status.textContent = `✓ "${name}" geloescht`;
} catch (e) {
- alert('Loeschen fehlgeschlagen: ' + e.message);
+ uiAlert('Loeschen fehlgeschlagen: ' + e.message);
}
}
@@ -8348,7 +8412,7 @@
async function deleteMemory(id) {
const m = brainMemoryCache[id];
const label = m ? `"${m.title}" (${m.type})` : id;
- if (!confirm(`Memory ${label} wirklich löschen?`)) return;
+ if (!await uiConfirm(`Memory ${label} wirklich löschen?`)) return;
try {
const r = await fetch('/api/brain/memory/delete/' + encodeURIComponent(id), { method: 'DELETE' });
if (!r.ok) throw new Error('HTTP ' + r.status);
@@ -8366,7 +8430,7 @@
else await loadBrainMemoryList();
loadBrainStatus();
} catch (e) {
- alert('Löschen fehlgeschlagen: ' + e.message);
+ uiAlert('Löschen fehlgeschlagen: ' + e.message);
}
}
@@ -8667,7 +8731,7 @@
// ── Migration aus brain-import/ ────────────────────────
async function runMigration() {
const status = document.getElementById('brain-import-files-status');
- if (!confirm('Migration starten?\n\nParst die Markdown-Dateien aus brain-import/ und schreibt sie als pinned Memory-Punkte in die DB. Bei Re-Run werden nur die Migration-Punkte ersetzt — eigene Memories bleiben.')) return;
+ if (!await uiConfirm('Migration starten?\n\nParst die Markdown-Dateien aus brain-import/ und schreibt sie als pinned Memory-Punkte in die DB. Bei Re-Run werden nur die Migration-Punkte ersetzt — eigene Memories bleiben.')) return;
if (status) status.innerHTML = '⏳ Migriere...';
try {
const r = await fetch('/api/brain/memory/migrate', { method: 'POST' });
@@ -8741,7 +8805,7 @@
const scopeInfo = bScope === 'system' ? 'Nur die aktuell pinned SYSTEM-Regeln werden ersetzt — Persönliches bleibt.'
: bScope === 'personal' ? 'Nur die aktuell pinned PERSÖNLICHEN Memories werden ersetzt — System-Regeln bleiben.'
: 'ALLE aktuell pinned Memories werden überschrieben.';
- if (!confirm(`Bootstrap importieren? (scope: ${bScope})\n\n${bundle.memories.length} pinned Memories aus "${file.name}".\n\n${scopeInfo} Cold Memory bleibt unverändert.`)) {
+ if (!await uiConfirm(`Bootstrap importieren? (scope: ${bScope})\n\n${bundle.memories.length} pinned Memories aus "${file.name}".\n\n${scopeInfo} Cold Memory bleibt unverändert.`)) {
event.target.value = '';
return;
}
@@ -8770,7 +8834,7 @@
const file = event.target.files[0];
if (!file) return;
const statusEl = document.getElementById('brain-import-status');
- if (!confirm(`Wirklich importieren? ALLE aktuellen Memories + Skills gehen verloren.\nDatei: ${file.name} (${(file.size/1024/1024).toFixed(1)} MB)`)) {
+ if (!await uiConfirm(`Wirklich importieren? ALLE aktuellen Memories + Skills gehen verloren.\nDatei: ${file.name} (${(file.size/1024/1024).toFixed(1)} MB)`)) {
event.target.value = '';
return;
}
@@ -8962,7 +9026,7 @@
}
async function unquarantineTurn(ts) {
- if (!confirm('Turn wieder in den Verlauf aufnehmen?\n\nWar er der Auslöser, '
+ if (!await uiConfirm('Turn wieder in den Verlauf aufnehmen?\n\nWar er der Auslöser, '
+ 'blockt Anthropics Filter beim nächsten Mal erneut — dann landet '
+ 'er automatisch wieder hier.')) return;
try {
@@ -8972,11 +9036,11 @@
});
if (!r.ok) throw new Error('HTTP ' + r.status);
loadSafeguard();
- } catch (e) { alert('Zurückholen fehlgeschlagen: ' + e.message); }
+ } catch (e) { uiAlert('Zurückholen fehlgeschlagen: ' + e.message); }
}
async function clearSafeguard() {
- if (!confirm('Vorfallsliste leeren?\n\nDanach läuft wieder das Hauptmodell — '
+ if (!await uiConfirm('Vorfallsliste leeren?\n\nDanach läuft wieder das Hauptmodell — '
+ 'auch in Projekten, die gerade aufs Ausweich-Modell ausweichen. '
+ 'Zurückgeholte Turns bleiben zurückgeholt.')) return;
try {
@@ -8986,7 +9050,7 @@
});
if (!r.ok) throw new Error('HTTP ' + r.status);
loadSafeguard();
- } catch (e) { alert('Leeren fehlgeschlagen: ' + e.message); }
+ } catch (e) { uiAlert('Leeren fehlgeschlagen: ' + e.message); }
}
// ── Datenschutz-Schalter ──────────────────────────────────────────
@@ -9681,11 +9745,11 @@
try {
const j = await (await fetch('/api/llm-catalog/add', { method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ hfRepo: repo }) })).json();
- if (!j.ok) { btn.disabled = false; btn.textContent = 'In Katalog'; alert('Nicht übernommen: ' + (j.error || 'Fehler')); return; }
+ if (!j.ok) { btn.disabled = false; btn.textContent = 'In Katalog'; uiAlert('Nicht übernommen: ' + (j.error || 'Fehler')); return; }
_llmCatalog = j.models || _llmCatalog;
renderLlmCatalog();
btn.outerHTML = 'im Katalog ✓ — dort „Laden"';
- } catch (e) { btn.disabled = false; btn.textContent = 'In Katalog'; alert(e.message); }
+ } catch (e) { btn.disabled = false; btn.textContent = 'In Katalog'; uiAlert(e.message); }
}
// ── Belege: was hat ARIA fuer eine Antwort wirklich ausgefuehrt? ──
@@ -9735,15 +9799,15 @@
// laden. Programme bekommen den neuen Wert automatisch (ctx in
// llm_cluster_models). Passt es nicht in den Grafikspeicher, setzt die Box
// die Karte auf den alten Stand zurueck.
- function onLlmCardCtx(sel) {
+ async function onLlmCardCtx(sel) {
const target = sel.dataset.box, gpu = sel.dataset.gpu, model = sel.dataset.model;
sel.blur(); // Fokus weg → aufgeschobenes Neuzeichnen holt den Stand nach
const cur = Number(sel.dataset.current || 0), next = Number(sel.value);
if (next === cur) return;
const m = _llmCatalog.find(x => x.id === model);
- if (!m || !m.hfRepo) { alert(`${model} steht nicht im Modell-Katalog — Kontext so nicht änderbar.`); sel.value = cur; return; }
+ if (!m || !m.hfRepo) { uiAlert(`${model} steht nicht im Modell-Katalog — Kontext so nicht änderbar.`); sel.value = cur; return; }
const more = next > cur;
- if (!confirm(`${model} auf ${_boxName(target)} · Karte ${gpu} mit ${next} statt ${cur || '?'} Tokens Kontext neu laden?\n\n`
+ if (!await uiConfirm(`${model} auf ${_boxName(target)} · Karte ${gpu} mit ${next} statt ${cur || '?'} Tokens Kontext neu laden?\n\n`
+ (more ? 'Mehr Kontext braucht mehr Grafikspeicher. Passt es nicht, setzt die Box die Karte von selbst auf den alten Stand zurück.\n\n' : '')
+ 'Die Box startet ihre Modelle dabei kurz neu. Programme bekommen den neuen Wert automatisch.')) { sel.value = cur; return; }
const sl = (workers.find(w => w.instanceId === target)?.slots || []).find(x => String(x.gpu) === String(gpu)) || {};
@@ -9758,13 +9822,13 @@
const node = _boxName(target);
if (next === current) return;
if (!next) {
- if (!confirm(`Karte ${gpu} auf ${node} leeren?\n\n${current} wird entladen; ARIA und Programme können es dann nicht mehr wählen. `
+ if (!await uiConfirm(`Karte ${gpu} auf ${node} leeren?\n\n${current} wird entladen; ARIA und Programme können es dann nicht mehr wählen. `
+ `Die Datei bleibt auf der Box.\n\nDie anderen Karten dieser Box starten dabei kurz neu.`)) { sel.value = current; return; }
send({ action: 'llm_unload_model', targetInstance: target, gpu });
return;
}
const m = _llmCatalog.find(x => x.id === next);
- if (!m || !m.hfRepo) { alert(`${next} steht nicht im Modell-Katalog — Herkunft unbekannt.`); sel.value = current; return; }
+ if (!m || !m.hfRepo) { uiAlert(`${next} steht nicht im Modell-Katalog — Herkunft unbekannt.`); sel.value = current; return; }
const sl = (workers.find(w => w.instanceId === target)?.slots || []).find(x => String(x.gpu) === String(gpu)) || {};
const vramGB = sl.vramMB ? sl.vramMB / 1024 : 0;
const cpuMoe = await askCpuMoe(m, sl.vramMB || 0);
@@ -9772,20 +9836,20 @@
const warn = (!cpuMoe && vramGB && m.sizeGB && m.sizeGB > vramGB * 0.92)
? `\n\n⚠ ${next} ist etwa ${m.sizeGB} GB groß, die Karte hat ${vramGB.toFixed(0)} GB — wahrscheinlich passt es nicht.` : '';
const repl = current ? `\n\nErsetzt ${current} — Programme, die es nutzen, verlieren es.` : '';
- if (!confirm(`${next} auf ${node} · Karte ${gpu} laden?${repl}${warn}\n\nDie anderen Karten dieser Box starten dabei kurz neu.`)) { sel.value = current; return; }
+ if (!await uiConfirm(`${next} auf ${node} · Karte ${gpu} laden?${repl}${warn}\n\nDie anderen Karten dieser Box starten dabei kurz neu.`)) { sel.value = current; return; }
send({ action: 'llm_provision_model', targetInstance: target, gpu, key: m.id, hfRepo: m.hfRepo, quant: m.quant, ctx: m.ctx, cpuMoe });
openLlmDownloads();
}
// MoE: Experten zwischen Karte und Arbeitsspeicher — gleiches Modell neu laden
- function onLlmCardMoe(sel) {
+ async function onLlmCardMoe(sel) {
const target = sel.dataset.box, gpu = sel.dataset.gpu, model = sel.dataset.model;
sel.blur(); // Fokus weg → aufgeschobenes Neuzeichnen holt den Stand nach
const cur = Number(sel.dataset.current || 0), next = Number(sel.value);
const m = _llmCatalog.find(x => x.id === model);
- if (!m || !m.hfRepo) { alert(`${model} steht nicht im Modell-Katalog.`); sel.value = String(cur); return; }
+ if (!m || !m.hfRepo) { uiAlert(`${model} steht nicht im Modell-Katalog.`); sel.value = String(cur); return; }
const txt = { '0': 'alle Experten auf die Karte', '-2': 'automatisch aufteilen (so viele wie passen auf die Karte)', '-1': 'alle Experten in den Arbeitsspeicher' };
- if (!confirm(`${model} neu laden: ${txt[String(next)] || next}?\n\nDie Box startet ihre Modelle dabei kurz neu.`)) { sel.value = String(cur); return; }
+ if (!await uiConfirm(`${model} neu laden: ${txt[String(next)] || next}?\n\nDie Box startet ihre Modelle dabei kurz neu.`)) { sel.value = String(cur); return; }
const sl = (workers.find(w => w.instanceId === target)?.slots || []).find(x => String(x.gpu) === String(gpu)) || {};
send({ action: 'llm_provision_model', targetInstance: target, gpu, key: m.id, hfRepo: m.hfRepo, quant: m.quant, ctx: sl.ctx || m.ctx, cpuMoe: next });
openLlmDownloads();
@@ -9817,8 +9881,8 @@
}).join('');
return `
${rows || 'Keine LLM-Karte konfiguriert (LLM_GPUS in der .env der Box).'}
`;
}
- function unloadLlmCard(instanceId, gpu, model) {
- if (!confirm(`Karte ${gpu} leeren?\n\n${model} wird entladen; Clients können es danach nicht mehr wählen. `
+ async function unloadLlmCard(instanceId, gpu, model) {
+ if (!await uiConfirm(`Karte ${gpu} leeren?\n\n${model} wird entladen; Clients können es danach nicht mehr wählen. `
+ `Die Datei bleibt auf der Box — erneutes Laden geht ohne Download.\n\n`
+ `Die anderen Karten dieser Box starten dabei kurz neu (wenige Sekunden).`)) return;
send({ action: 'llm_unload_model', targetInstance: instanceId, gpu });
@@ -9874,18 +9938,18 @@
});
}
- function deleteLlmFiles(instanceId, i) {
+ async function deleteLlmFiles(instanceId, i) {
const m = _llmCatalog[i];
if (!m) return;
const b = onlineLlmBoxes().find(w => w.instanceId === instanceId);
const d = ((b && b.disk && b.disk.models) || []).find(x => x.repo === m.hfRepo);
- if (!confirm(`${m.id} von ${(b && b.node) || instanceId} löschen?\n\n`
+ if (!await uiConfirm(`${m.id} von ${(b && b.node) || instanceId} löschen?\n\n`
+ `Die heruntergeladene Datei (${d ? _fmtBytes(d.bytes) : '?'}, Repo ${m.hfRepo}) wird von der Box entfernt. `
+ `Wer es wieder will, muss es neu herunterladen.`)) return;
send({ action: 'llm_remove_model', targetInstance: instanceId, key: m.id, hfRepo: m.hfRepo, deleteFiles: true });
}
- function cancelLlmJob(instanceId, key) {
- if (!confirm(`Laden von ${key} abbrechen?\n\nDer halbe Download wird gelöscht, die Karte bleibt bzw. wird wie vorher.`)) return;
+ async function cancelLlmJob(instanceId, key) {
+ if (!await uiConfirm(`Laden von ${key} abbrechen?\n\nDer halbe Download wird gelöscht, die Karte bleibt bzw. wird wie vorher.`)) return;
send({ action: 'llm_remove_model', targetInstance: instanceId, key, cancel: true });
}
@@ -9896,11 +9960,11 @@
const [target, gpu] = String((sel && sel.value) || '').split('|');
if (!target) return;
const tgt = llmCardTargets().find(t => t.value === sel.value);
- if (tgt && tgt.slot && tgt.slot.model === m.id) { alert(`${m.id} liegt schon auf dieser Karte.`); return; }
+ if (tgt && tgt.slot && tgt.slot.model === m.id) { uiAlert(`${m.id} liegt schon auf dieser Karte.`); return; }
const busyBox = ((tgt && tgt.box.slots) || []).find(sl => sl.model === m.id);
- if (busyBox) { alert(`${m.id} liegt auf dieser Box schon auf Karte ${busyBox.gpu}. Ein Modell pro Box nur einmal.`); return; }
+ if (busyBox) { uiAlert(`${m.id} liegt auf dieser Box schon auf Karte ${busyBox.gpu}. Ein Modell pro Box nur einmal.`); return; }
if (tgt && tgt.slot && tgt.slot.model &&
- !confirm(`Karte ${gpu} auf ${tgt.box.node} hält gerade ${tgt.slot.model}.\n\n`
+ !await uiConfirm(`Karte ${gpu} auf ${tgt.box.node} hält gerade ${tgt.slot.model}.\n\n`
+ `${m.id} ersetzt es. Clients, die ${tgt.slot.model} nutzen, verlieren es dann.\n`
+ `Die anderen Karten dieser Box starten dabei kurz neu.\n\nErsetzen?`)) return;
const cpuMoe = await askCpuMoe(m, (tgt && tgt.slot && tgt.slot.vramMB) || 0);
@@ -9974,10 +10038,10 @@
// den Klick, wenn der Browser Dialoge unterdrueckt hatte ("Verhindern,
// dass diese Seite weitere Dialoge erstellt") → confirm()===false → es ging
// NICHTS raus. Nur "aggressive" (Volumes!) fragt noch nach.
- function runDiskCleanup(variant) {
+ async function runDiskCleanup(variant) {
const aggressive = variant === 'aggressive';
if (aggressive) {
- const ok = confirm('AGGRESSIV aufraeumen? Loescht zusaetzlich ungenutzte Volumes — nur wenn ALLE ARIA-Container laufen, sonst Datenverlust!');
+ const ok = await uiConfirm('AGGRESSIV aufraeumen? Loescht zusaetzlich ungenutzte Volumes — nur wenn ALLE ARIA-Container laufen, sonst Datenverlust!');
if (!ok) return;
}
const btn = document.getElementById('disk-clean-btn');
@@ -9994,7 +10058,7 @@
btn.textContent = 'Kopiert!';
setTimeout(() => { btn.textContent = old; }, 1500);
}).catch(() => {
- alert('Kopieren fehlgeschlagen — Befehl: ' + cmd);
+ uiAlert('Kopieren fehlgeschlagen — Befehl: ' + cmd);
});
}