diff --git a/diagnostic/index.html b/diagnostic/index.html
index ad4224f..d510269 100644
--- a/diagnostic/index.html
+++ b/diagnostic/index.html
@@ -852,8 +852,32 @@
+
+
@@ -3451,6 +3475,98 @@
const p = document.getElementById('brain-filter-pinned'); if (p) p.value = 'all';
const info = document.getElementById('brain-search-info'); if (info) info.style.display = 'none';
brainSearchIds = null;
+ clearAdvancedSearch();
+ }
+
+ function toggleAdvancedSearch() {
+ const panel = document.getElementById('brain-advanced-panel');
+ const btn = document.getElementById('btn-advanced-search');
+ if (!panel) return;
+ const open = panel.style.display !== 'none';
+ panel.style.display = open ? 'none' : 'block';
+ if (btn) btn.textContent = open ? '⌃ Erweitert' : '⌄ Einklappen';
+ }
+
+ function clearAdvancedSearch() {
+ ['adv-term-1','adv-term-2','adv-term-3'].forEach(id => {
+ const el = document.getElementById(id); if (el) el.value = '';
+ });
+ }
+
+ /** Mehrere Volltext-Suchen + Boolean-Kombination (links nach rechts).
+ * Backend bleibt simpel — wir machen N parallele search-text-Calls
+ * und kombinieren die ID-Mengen client-seitig per AND/OR. */
+ async function runAdvancedSearch() {
+ const terms = [
+ document.getElementById('adv-term-1')?.value?.trim() || '',
+ document.getElementById('adv-term-2')?.value?.trim() || '',
+ document.getElementById('adv-term-3')?.value?.trim() || '',
+ ];
+ const ops = [
+ document.getElementById('adv-op-1')?.value || 'AND',
+ document.getElementById('adv-op-2')?.value || 'AND',
+ ];
+ const info = document.getElementById('brain-search-info');
+ // Felder mit Inhalt zusammen mit dem ops-Op DAVOR sammeln
+ const active = [];
+ for (let i = 0; i < 3; i++) {
+ if (terms[i]) active.push({ term: terms[i], op: i === 0 ? null : ops[i - 1] });
+ }
+ if (active.length === 0) {
+ if (info) info.style.display = 'none';
+ loadBrainMemoryList();
+ return;
+ }
+
+ const typeFilter = document.getElementById('brain-filter-type').value;
+ const baseParams = { k: '500', include_pinned: 'true' };
+ if (typeFilter) baseParams.type = typeFilter;
+
+ try {
+ // Pro Begriff einmal Backend fragen, dann Map + Set
+ const sets = [];
+ for (const a of active) {
+ const params = new URLSearchParams({ ...baseParams, q: a.term });
+ const r = await fetch('/api/brain/memory/search-text?' + params.toString());
+ if (!r.ok) throw new Error('HTTP ' + r.status);
+ const hits = await r.json();
+ hits.forEach(m => { brainMemoryCache[m.id] = m; });
+ sets.push(new Set(hits.map(m => m.id)));
+ }
+
+ // Links-nach-rechts kombinieren mit den Operatoren
+ let combined = sets[0];
+ for (let i = 1; i < sets.length; i++) {
+ const op = active[i].op;
+ if (op === 'AND') {
+ combined = new Set([...combined].filter(id => sets[i].has(id)));
+ } else {
+ combined = new Set([...combined, ...sets[i]]);
+ }
+ }
+
+ const hits = Array.from(combined).map(id => brainMemoryCache[id]).filter(Boolean);
+ brainSearchIds = hits.map(m => m.id);
+ const desc = active.map((a, i) => i === 0 ? `"${a.term}"` : ` ${a.op} "${a.term}"`).join('');
+ if (info) {
+ info.style.display = 'block';
+ if (hits.length === 0) {
+ info.innerHTML = `🔍 Keine Treffer fuer ${escapeHtml(desc)}` +
+ (typeFilter ? ` · Typ=${escapeHtml(typeFilter)}` : '') +
+ ` · 📝 wortlich, Boolean-Kombi`;
+ } else {
+ info.innerHTML = `🔍 ${hits.length} Treffer fuer ${escapeHtml(desc)}` +
+ (typeFilter ? ` · Typ=${escapeHtml(typeFilter)}` : '') +
+ ` · 📝 wortlich, Boolean-Kombi`;
+ }
+ }
+ renderBrainList(hits, true);
+ } catch (e) {
+ if (info) {
+ info.style.display = 'block';
+ info.innerHTML = `🔴 Erweiterte Suche fehlgeschlagen: ${escapeHtml(e.message)}`;
+ }
+ }
}
async function runBrainSearch() {