Phase 7: Agent Selector — per-agent soul.md + ChromaDB memory filtering

- Agent dropdown UI (chip button + hidden select) in composer header
- Session.agent field persists agent selection across refresh
- soul.md loaded per-agent via ephemeral_system_prompt injection
- ChromaDB memory filtered by agent topic (lotus/, sunflower/, etc.)
- Fixed streaming.py: agent→_ai_agent variable shadowing (lines 1161, 1163)
- New API endpoints: /api/agents/topology, /api/agents/memory/search
- Agent metadata registry with emoji, name, description per Tier-2 agent
This commit is contained in:
Rose
2026-04-20 17:34:58 +02:00
parent 00045314f8
commit c705fad626
14 changed files with 2578 additions and 320 deletions

View File

@@ -22,10 +22,12 @@
<button class="nav-tab" data-panel="tasks" data-label="Tasks" onclick="switchPanel('tasks')" title="Tasks" data-i18n-title="tab_tasks"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="4" width="18" height="18" rx="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg></button>
<button class="nav-tab" data-panel="skills" data-label="Skills" onclick="switchPanel('skills')" title="Skills" data-i18n-title="tab_skills"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 2L2 7l10 5 10-5-10-5z"/><path d="M2 17l10 5 10-5"/><path d="M2 12l10 5 10-5"/></svg></button>
<button class="nav-tab" data-panel="memory" data-label="Memory" onclick="switchPanel('memory')" title="Memory" data-i18n-title="tab_memory"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 2a7 7 0 0 1 7 7c0 2.5-1.3 4.7-3.2 6H8.2C6.3 13.7 5 11.5 5 9a7 7 0 0 1 7-7z"/><line x1="9" y1="17" x2="15" y2="17"/><line x1="10" y1="20" x2="14" y2="20"/></svg></button>
<button class="nav-tab" data-panel="workspaces" data-label="Spaces" onclick="switchPanel('workspaces')" title="Spaces" data-i18n-title="tab_workspaces"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/></svg></button>
<button class="nav-tab" data-panel="todos" data-label="Todos" onclick="switchPanel('todos')" title="Current task list" data-i18n-title="tab_todos"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="5" width="6" height="6" rx="1"/><path d="m3 17 2 2 4-4"/><path d="M13 6h8"/><path d="M13 12h8"/><path d="M13 18h8"/></svg></button>
<button class="nav-tab" data-panel="missioncontrol" data-label="MC" onclick="switchPanel('missioncontrol')" title="Mission Control" data-i18n-title="tab_mc"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg></button>
<button class="nav-tab" data-panel="agents" data-label="Agents" onclick="switchPanel('agents')" title="Rose + Tier-2 Agents" data-i18n-title="tab_agents"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg></button>
<button class="nav-tab" data-panel="projects" data-label="Projects" onclick="switchPanel('projects')" title="Projects & Tasks" data-i18n-title="tab_projects"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/></svg></button>
</div>
<!-- Chat panel -->
<div class="panel-view active" id="panelChat">
@@ -104,84 +106,8 @@
<div id="memEditError" style="font-size:11px;color:var(--accent);margin-top:6px;display:none"></div>
</div>
</div>
<!-- Todo panel -->
<div class="panel-view" id="panelTodos">
<div style="padding:10px 12px 4px;font-size:11px;color:var(--muted);flex-shrink:0" data-i18n="current_task_list">Current task list</div>
<div id="todoPanel" style="flex:1;overflow-y:auto;padding:8px 12px"></div>
</div>
<!-- Mission Control panel -->
<div class="panel-view" id="panelMissioncontrol">
<!-- Header -->
<div style="padding:14px 16px 10px;flex-shrink:0;border-bottom:1px solid var(--border)">
<div style="display:flex;align-items:center;justify-content:space-between">
<div style="display:flex;align-items:center;gap:8px">
<span style="font-size:16px">🎯</span>
<span style="font-size:14px;font-weight:700;color:var(--text)">Mission Control</span>
</div>
<div style="display:flex;align-items:center;gap:6px">
<span id="mcHealthBadge" style="font-size:10px;font-weight:600;padding:2px 8px;border-radius:12px;background:rgba(0,0,0,.06)"></span>
<button onclick="refreshMC()" title="Refresh" style="background:none;border:none;cursor:pointer;color:var(--muted);font-size:12px;padding:2px"></button>
</div>
</div>
</div>
<!-- Stats Cards -->
<div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;padding:10px 16px;flex-shrink:0">
<div style="background:var(--surface);border-radius:10px;padding:10px 12px;border:1px solid var(--border)">
<div style="font-size:10px;color:var(--muted);margin-bottom:2px">Tasks</div>
<div style="font-size:18px;font-weight:700;color:var(--blue)" id="mcTasksCount"></div>
<div style="font-size:9px;color:var(--muted)" id="mcTasksLabel">loading...</div>
</div>
<div style="background:var(--surface);border-radius:10px;padding:10px 12px;border:1px solid var(--border)">
<div style="font-size:10px;color:var(--muted);margin-bottom:2px">Priorities</div>
<div style="font-size:18px;font-weight:700;color:var(--gold)" id="mcPrioritiesCount"></div>
<div style="font-size:9px;color:var(--muted)" id="mcPrioritiesLabel">loading...</div>
</div>
</div>
<!-- Progress Bar -->
<div style="padding:0 16px 10px;flex-shrink:0">
<div style="display:flex;justify-content:space-between;font-size:9px;color:var(--muted);margin-bottom:4px">
<span>Progress</span><span id="mcProgressPct">0%</span>
</div>
<div style="background:var(--border);border-radius:6px;height:8px;overflow:hidden">
<div id="mcProgressBar" style="height:100%;width:0%;background:linear-gradient(90deg,var(--blue),var(--accent));border-radius:6px;transition:width .4s ease"></div>
</div>
</div>
<!-- Add Task -->
<div style="padding:0 16px 10px;flex-shrink:0">
<div style="font-size:10px;font-weight:600;color:var(--muted);margin-bottom:6px;text-transform:uppercase;letter-spacing:.05em">New Task</div>
<input id="mcNewTaskTitle" placeholder="What needs to be done?" style="width:100%;background:var(--input-bg);border:1px solid var(--border);border-radius:8px;padding:8px 10px;font-size:12px;color:var(--text);outline:none;margin-bottom:6px" onkeydown="if(event.key==='Enter')createMCTask()">
<div style="display:grid;grid-template-columns:1fr 1fr 80px;gap:6px">
<select id="mcNewTaskPriority" style="background:var(--input-bg);border:1px solid var(--border);border-radius:8px;padding:6px 8px;font-size:11px;color:var(--text);outline:none">
<option value="1">🔴 Critical</option>
<option value="2" selected>🟠 High</option>
<option value="3">🟡 Medium</option>
<option value="4">🟢 Low</option>
</select>
<select id="mcNewTaskStatus" style="background:var(--input-bg);border:1px solid var(--border);border-radius:8px;padding:6px 8px;font-size:11px;color:var(--text);outline:none">
<option value="backlog" selected>○ Backlog</option>
<option value="progress">◐ In Progress</option>
</select>
<button onclick="createMCTask()" style="background:var(--accent);border:none;border-radius:8px;padding:6px 10px;font-size:11px;font-weight:600;color:#fff;cursor:pointer">Add</button>
</div>
</div>
<!-- Priority Filter -->
<div style="padding:0 16px 6px;flex-shrink:0">
<div style="display:flex;gap:4px;flex-wrap:wrap" id="mcPriorityFilters"></div>
</div>
<!-- Tasks List -->
<div style="flex:1;overflow-y:auto;padding:0 16px" id="mcTasksList"></div>
<!-- Feed -->
<div style="padding:8px 16px 4px;border-top:1px solid var(--border);flex-shrink:0">
<div style="font-size:10px;font-weight:600;color:var(--muted);text-transform:uppercase;letter-spacing:.05em;margin-bottom:6px">Recent Activity</div>
</div>
<div id="mcFeed" style="flex-shrink:0;max-height:100px;overflow-y:auto;padding:0 16px 12px;font-size:10px;color:var(--muted)"></div>
</div>
<!-- Agents panel (Rose + Tier-2) -->
<div class="panel-view" id="panelAgents">
<div style="padding:14px 16px 10px;flex-shrink:0;border-bottom:1px solid var(--border)">
@@ -194,17 +120,103 @@
</div>
<div style="font-size:10px;color:var(--muted);margin-top:4px">Rose + 7 Tier-2 Domain Agents</div>
</div>
<!-- Agents list -->
<!-- agents list -->
<div style="flex:1;overflow-y:auto;padding:10px 16px" id="agentsList">
<div style="color:var(--muted);font-size:12px;text-align:center;padding:20px">Loading...</div>
</div>
<!-- Agent inbox slide-in panel -->
<div id="agentInbox" style="display:none;position:absolute;top:0;right:0;bottom:0;width:320px;background:var(--surface);border-left:1px solid var(--border);z-index:100;overflow-y:auto;padding:16px;box-shadow:-4px 0 20px rgba(0,0,0,.3)"></div>
</div>
<!-- Workspaces panel -->
<div class="panel-view" id="panelWorkspaces">
<div style="padding:10px 12px 4px;font-size:11px;color:var(--muted)" data-i18n="workspace_desc">Add and switch workspaces for your sessions.</div>
<div style="flex:1;overflow-y:auto;padding:0 12px 12px" id="workspacesPanel"><div style="color:var(--muted);font-size:12px" data-i18n="loading">Loading...</div></div>
<!-- Projects panel -->
<div class="panel-view" id="panelProjects">
<!-- Header: Title + Expand Button -->
<div class="projects-header">
<div class="projects-title">📋 Projects</div>
<div class="projects-header-stats" id="projectsHeaderStats"></div>
<button class="panel-icon-btn" id="btnExpandProjects" title="Expand" onclick="expandPanel('projects')">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 3 21 3 21 9"/><polyline points="9 21 3 21 3 15"/><line x1="21" y1="3" x2="14" y2="10"/><line x1="3" y1="21" x2="10" y2="14"/></svg>
</button>
</div>
<!-- Quick Add Bar -->
<div class="projects-quick-add">
<span class="quick-add-icon">+</span>
<input id="quickAddInput" placeholder="Add a task..." onkeydown="if(event.key==='Enter')quickAddTask()">
<input id="quickAddDue" type="date" title="Due date" id="quickAddDue">
<select id="quickAddType">
<option value="project">📁 Project</option>
<option value="daily">📅 Daily</option>
<option value="recurring">🔄 Recurring</option>
</select>
<button class="quick-add-btn" onclick="quickAddTask()">Add</button>
</div>
<!-- Filter Bar -->
<div class="projects-filter-bar" id="projectsFilterBar">
<div class="filter-group">
<button class="filter-btn active" data-filter="all" onclick="filterTasks('all')">All</button>
<button class="filter-btn" data-filter="project" onclick="filterTasks('project')">📁 Projects</button>
<button class="filter-btn" data-filter="daily" onclick="filterTasks('daily')">📅 Daily</button>
<button class="filter-btn" data-filter="recurring" onclick="filterTasks('recurring')">🔄 Recurring</button>
</div>
<div class="filter-sep"></div>
<div class="filter-group">
<button class="filter-btn p1" onclick="filterTasks('p1')">🔴 P1</button>
<button class="filter-btn p2" onclick="filterTasks('p2')">🟡 P2</button>
<button class="filter-btn p3" onclick="filterTasks('p3')">🟢 P3</button>
</div>
<div class="filter-sep"></div>
<div class="filter-group filter-group-right">
<span class="filter-streak" id="filterStreak"></span>
<span class="filter-overdue" id="filterOverdue"></span>
</div>
</div>
<!-- Main Content: Split View -->
<div class="projects-main" id="projectsMain">
<!-- Linke Spalte: Projektliste -->
<div class="projects-sidebar" id="projectsSidebar">
<div class="sidebar-section-header">📁 Projects</div>
<div id="projectsList"></div>
<div class="sidebar-section-header" style="margin-top:16px">📅 Daily Tasks</div>
<div id="dailyTasksList"></div>
<div class="sidebar-section-header" style="margin-top:16px">🔄 Recurring</div>
<div id="recurringTasksList"></div>
</div>
<!-- Rechte Spalte: Globales Kanban -->
<div class="projects-kanban" id="projectsKanban">
<div class="kanban-col" ondragover="onKanbanDragOver(event)" ondrop="onKanbanDrop(event, 'todo')">
<div class="kanban-col-header">
<span class="kanban-col-title">📋 TODO</span>
<span class="kanban-col-count" id="kanbanTodoCount"></span>
</div>
<div class="kanban-col-content" id="kanbanTodoContent"></div>
</div>
<div class="kanban-col" ondragover="onKanbanDragOver(event)" ondrop="onKanbanDrop(event, 'in_progress')">
<div class="kanban-col-header">
<span class="kanban-col-title">⚡ IN PROGRESS</span>
<span class="kanban-col-count" id="kanbanInProgressCount"></span>
</div>
<div class="kanban-col-content" id="kanbanInProgressContent"></div>
</div>
<div class="kanban-col" ondragover="onKanbanDragOver(event)" ondrop="onKanbanDrop(event, 'review')">
<div class="kanban-col-header">
<span class="kanban-col-title">👀 REVIEW</span>
<span class="kanban-col-count" id="kanbanReviewCount"></span>
</div>
<div class="kanban-col-content" id="kanbanReviewContent"></div>
</div>
<div class="kanban-col" ondragover="onKanbanDragOver(event)" ondrop="onKanbanDrop(event, 'done')">
<div class="kanban-col-header">
<span class="kanban-col-title">✅ DONE</span>
<span class="kanban-col-count" id="kanbanDoneCount"></span>
</div>
<div class="kanban-col-content" id="kanbanDoneContent"></div>
</div>
</div>
</div>
</div>
<div class="sidebar-bottom">
@@ -242,6 +254,14 @@
</button>
<div style="flex:1;min-width:0;overflow:hidden"><div class="topbar-title" id="topbarTitle">Hermes</div><div class="topbar-meta" id="topbarMeta" data-i18n="new_conversation">Start a new conversation</div></div>
<div class="topbar-chips">
<div class="ws-selector-wrap" id="wsSelectorWrap" style="position:relative">
<button class="chip ws-selector-chip" id="wsSelectorChip" type="button" onclick="toggleWsSelectorDropdown()" title="Switch workspace">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/></svg>
<span id="wsSelectorLabel">Workspace</span>
<svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg>
</button>
<div class="ws-selector-dropdown" id="wsSelectorDropdown" style="display:none;position:absolute;top:100%;left:0;margin-top:4px;background:var(--surface);border:1px solid var(--border);border-radius:10px;min-width:260px;max-height:320px;overflow-y:auto;z-index:200;box-shadow:0 8px 24px rgba(0,0,0,.3)"></div>
</div>
<button class="chip workspace-toggle-btn" id="btnWorkspacePanelToggle" onclick="toggleWorkspacePanel()" title="Show workspace panel" aria-pressed="false"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/></svg><span class="workspace-toggle-label">Files</span></button>
</div>
</div>
@@ -361,21 +381,6 @@
<line x1="8" y1="23" x2="16" y2="23"/>
</svg>
</button>
<div class="composer-divider" aria-hidden="true"></div>
<div id="profileChipWrap" class="composer-profile-wrap">
<button class="composer-profile-chip profile-chip" id="profileChip" type="button" onclick="toggleProfileDropdown()" title="Switch profile">
<span class="composer-profile-icon" aria-hidden="true"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg></span>
<span class="composer-profile-label" id="profileChipLabel">default</span>
<span class="composer-profile-chevron" aria-hidden="true"><svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg></span>
</button>
</div>
<div class="composer-ws-wrap">
<button class="composer-workspace-chip ws-chip" id="composerWorkspaceChip" type="button" onclick="toggleComposerWsDropdown()" title="Switch workspace" disabled>
<span class="composer-workspace-icon" aria-hidden="true"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/></svg></span>
<span class="composer-workspace-label" id="composerWorkspaceLabel">Workspace</span>
<span class="composer-workspace-chevron" aria-hidden="true"><svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg></span>
</button>
</div>
<div class="composer-model-wrap">
<button class="composer-model-chip" id="composerModelChip" type="button" onclick="toggleModelDropdown()" title="Conversation model">
<span class="composer-model-icon" aria-hidden="true"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="4" width="16" height="16" rx="2"/><rect x="9" y="9" width="6" height="6"/><path d="M15 2v2"/><path d="M15 20v2"/><path d="M2 15h2"/><path d="M2 9h2"/><path d="M20 15h2"/><path d="M20 9h2"/><path d="M9 2v2"/><path d="M9 20v2"/></svg></span>
@@ -401,6 +406,23 @@
</optgroup>
</select>
</div>
<div class="composer-agent-wrap">
<button class="composer-agent-chip" id="composerAgentChip" type="button" onclick="toggleAgentDropdown()" title="Chat with agent">
<span class="composer-agent-icon" id="composerAgentIcon" aria-hidden="true">🌹</span>
<span class="composer-agent-label" id="composerAgentLabel">Rose</span>
<span class="composer-agent-chevron" aria-hidden="true"><svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg></span>
</button>
<select id="agentSelect" class="composer-agent-select" title="Chat with agent" aria-hidden="true" tabindex="-1">
<option value="rose">🌹 Rose</option>
<option value="lotus">🪷 Lotus</option>
<option value="forget-me-not">🌼 Forget-me-not</option>
<option value="sunflower">🌻 Sunflower</option>
<option value="iris">⚜️ Iris</option>
<option value="ivy">🌿 Ivy</option>
<option value="dandelion">🛡️ Dandelion</option>
<option value="root">🌳 Root</option>
</select>
</div>
</div>
<div class="composer-right">
<span class="composer-status" id="composerStatus" style="display:none"></span>
@@ -432,6 +454,7 @@
<div class="profile-dropdown" id="profileDropdown"></div>
<div class="ws-dropdown ws-dropdown-footer" id="composerWsDropdown"></div>
<div class="model-dropdown" id="composerModelDropdown"></div>
<div class="agent-dropdown" id="composerAgentDropdown"></div>
</div>
<div class="upload-bar-wrap" id="uploadBarWrap"><div class="upload-bar" id="uploadBar"></div></div>
</div>
@@ -473,6 +496,72 @@
</div>
</aside>
</div>
<!-- Task Detail Modal -->
<div id="taskDetailModal" class="modal-overlay" style="display:none" onclick="if(event.target===this)closeTaskModal()">
<div class="modal-card">
<div class="modal-header">
<div class="modal-title" id="taskModalTitle"></div>
<button class="modal-close" onclick="closeTaskModal()">×</button>
</div>
<div class="modal-body">
<div class="modal-field">
<label>Title</label>
<input id="taskModalInputTitle" class="modal-input" type="text" placeholder="Task title...">
</div>
<div class="modal-field-row">
<div class="modal-field">
<label>Status</label>
<select id="taskModalSelectStatus" class="modal-select">
<option value="todo">Todo</option>
<option value="in_progress">In Progress</option>
<option value="review">Review</option>
<option value="done">Done</option>
</select>
</div>
<div class="modal-field">
<label>Priority</label>
<select id="taskModalSelectPrio" class="modal-select">
<option value="p1">🔴 P1 — Critical</option>
<option value="p2">🟡 P2 — Normal</option>
<option value="p3">🟢 P3 — Low</option>
</select>
</div>
</div>
<div class="modal-field-row">
<div class="modal-field">
<label>Due Date</label>
<input id="taskModalInputDue" class="modal-input" type="date">
</div>
<div class="modal-field">
<label>Owner</label>
<select id="taskModalSelectOwner" class="modal-select">
<option value="user">👤 Sabo</option>
<option value="rose">🌹 Rose</option>
<option value="agent:lotus">🪷 Lotus</option>
<option value="agent:sunflower">🌻 Sunflower</option>
<option value="agent:iris">⚜️ Iris</option>
<option value="agent:ivy">🌿 Ivy</option>
<option value="agent:dandelion">🛡️ Dandelion</option>
<option value="agent:root">🌳 Root</option>
</select>
</div>
</div>
<div class="modal-field">
<label>Tags (comma-separated)</label>
<input id="taskModalInputTags" class="modal-input" type="text" placeholder="webui, api, bug...">
</div>
<div class="modal-meta" id="taskModalMeta"></div>
</div>
<div class="modal-footer">
<button class="modal-btn-danger" id="taskModalDeleteBtn" onclick="deleteTaskFromModal()">Delete</button>
<div style="flex:1"></div>
<button class="modal-btn-secondary" onclick="closeTaskModal()">Cancel</button>
<button class="modal-btn-primary" onclick="saveTaskFromModal()">Save</button>
</div>
</div>
</div>
<div class="onboarding-overlay" id="onboardingOverlay" style="display:none" role="dialog" aria-modal="true" aria-labelledby="onboardingTitle">
<div class="onboarding-card">
<div class="onboarding-shell">
@@ -527,6 +616,10 @@
<svg class="settings-tab-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><polyline points="10 9 9 9 8 9"/></svg>
<span class="settings-tab-title">Logs</span>
</button>
<button class="settings-tab" id="settingsTabHeartbeats" type="button" role="tab" aria-selected="false" aria-controls="settingsPaneHeartbeats" onclick="switchSettingsSection('heartbeats')">
<svg class="settings-tab-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"/></svg>
<span class="settings-tab-title">Heartbeats</span>
</button>
</div>
<div class="settings-main">
<div class="settings-pane active" id="settingsPaneConversation" role="tabpanel" aria-labelledby="settingsTabConversation">
@@ -689,19 +782,30 @@
<input type="checkbox" id="logsAutoRefresh" onchange="toggleLogAutoRefresh()" style="width:13px;height:13px;accent-color:var(--accent)">
Live
</label>
<button class="sm-btn" id="btnRefreshLog" onclick="refreshLogManual()" style="display:none;padding:3px 8px;font-size:11px">Refresh</button>
<button class="icon-btn" id="logsRefreshBtn" style="display:none" onclick="loadLogsPanel()" title="Refresh logs">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="23 4 23 10 17 10"/><polyline points="1 20 1 14 7 14"/><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"/></svg>
</button>
</div>
</div>
<pre class="logs-pre" id="logsContent"><span style="color:var(--muted);font-size:12px">Select a log file from the list to view its contents.</span></pre>
<div class="logs-footer" id="logsFooter" style="display:none;font-size:10px;color:var(--muted);padding:4px 12px;border-top:1px solid var(--border)">
<span id="logsMatchCount"></span>
<div class="logs-body" id="logsBody">
<div style="color:var(--muted);font-size:12px;padding:20px;text-align:center" id="logsEmptyState">Select a log file from the sidebar to view its contents.</div>
<div id="logsContent" style="display:none"></div>
</div>
</div>
</div>
</div>
<div class="settings-pane" id="settingsPaneHeartbeats" role="tabpanel" aria-labelledby="settingsTabHeartbeats">
<div class="settings-section-head">
<div>
<div class="settings-section-title">Heartbeats</div>
<div class="settings-section-meta">Proaktive zeitbasierte Callbacks für Rose.</div>
</div>
</div>
<div id="heartbeatsPanelContent" style="padding:16px">
<div style="color:var(--muted);font-size:12px;text-align:center;padding:20px">Lädt...</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
@@ -733,5 +837,93 @@
<script src="/static/panels.js"></script>
<script src="/static/onboarding.js"></script>
<script src="/static/boot.js"></script>
<!-- Task Edit Modal -->
<div id="taskEditModal" class="modal-overlay" style="display:none;position:fixed;inset:0;background:rgba(0,0,0,.6);z-index:2000;justify-content:center;align-items:center">
<div style="background:var(--surface);border:1px solid var(--border2);border-radius:12px;padding:24px;width:420px;max-width:90vw">
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:20px">
<span style="font-weight:600;font-size:15px;color:var(--text)">Edit Task</span>
<button onclick="closeTaskEditModal()" style="background:none;border:none;color:var(--text-secondary);cursor:pointer;font-size:18px;padding:4px"></button>
</div>
<input id="editTaskTitle" style="width:100%;padding:10px 12px;background:var(--bg);border:1px solid var(--border2);border-radius:8px;color:var(--text);font-size:14px;box-sizing:border-box;margin-bottom:12px;outline:none">
<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:12px">
<div>
<label style="font-size:11px;color:var(--text-secondary);display:block;margin-bottom:4px">TYPE</label>
<select id="editTaskType" onchange="onEditTypeChange()" style="width:100%;padding:8px;background:var(--bg);border:1px solid var(--border2);border-radius:6px;color:var(--text);font-size:13px;outline:none">
<option value="project">Project</option>
<option value="daily">Daily</option>
<option value="recurring">Recurring</option>
</select>
</div>
<div>
<label style="font-size:11px;color:var(--text-secondary);display:block;margin-bottom:4px">PRIORITY</label>
<select id="editTaskPriority" style="width:100%;padding:8px;background:var(--bg);border:1px solid var(--border2);border-radius:6px;color:var(--text);font-size:13px;outline:none">
<option value="p1">🔴 P1 — Critical</option>
<option value="p2">🟡 P2 — High</option>
<option value="p3">🟢 P3 — Normal</option>
</select>
</div>
</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:12px">
<div>
<label style="font-size:11px;color:var(--text-secondary);display:block;margin-bottom:4px">PROJECT</label>
<select id="editTaskProject" style="width:100%;padding:8px;background:var(--bg);border:1px solid var(--border2);border-radius:6px;color:var(--text);font-size:13px;outline:none">
<option value="">— None —</option>
</select>
</div>
<div>
<label style="font-size:11px;color:var(--text-secondary);display:block;margin-bottom:4px">DUE DATE</label>
<input id="editTaskDue" type="date" style="width:100%;padding:8px;background:var(--bg);border:1px solid var(--border2);border-radius:6px;color:var(--text);font-size:13px;outline:none;box-sizing:border-box;color-scheme:dark">
</div>
</div>
<div id="editTaskRecurringOpts" style="display:none;margin-bottom:12px">
<label style="font-size:11px;color:var(--text-secondary);display:block;margin-bottom:4px">RECURRING — EVERY</label>
<div style="display:flex;gap:8px;align-items:center">
<input id="editRecInterval" type="number" min="1" value="1" style="width:60px;padding:8px;background:var(--bg);border:1px solid var(--border2);border-radius:6px;color:var(--text);font-size:13px;text-align:center;outline:none">
<select id="editRecUnit" style="padding:8px;background:var(--bg);border:1px solid var(--border2);border-radius:6px;color:var(--text);font-size:13px;outline:none">
<option value="days">day(s)</option>
<option value="weeks">week(s)</option>
<option value="months">month(s)</option>
</select>
</div>
</div>
<div style="display:flex;gap:8px;justify-content:space-between;margin-top:16px">
<button onclick="deleteTask(editingTaskId)" style="padding:8px 16px;background:rgba(239,68,68,.15);border:1px solid rgba(239,68,68,.3);border-radius:8px;color:#ef4444;cursor:pointer;font-size:13px">🗑 Delete</button>
<div style="display:flex;gap:8px">
<button onclick="closeTaskEditModal()" style="padding:8px 16px;background:var(--bg);border:1px solid var(--border2);border-radius:8px;color:var(--text);cursor:pointer;font-size:13px">Cancel</button>
<button onclick="saveTaskEdit()" style="padding:8px 16px;background:var(--accent);border:none;border-radius:8px;color:#fff;cursor:pointer;font-size:13px;font-weight:500">Save Changes</button>
</div>
</div>
</div>
</div>
<!-- Project Edit Modal -->
<div id="projectEditModal" class="modal-overlay" style="display:none;position:fixed;inset:0;background:rgba(0,0,0,.6);z-index:2000;justify-content:center;align-items:center">
<div style="background:var(--surface);border:1px solid var(--border2);border-radius:12px;padding:24px;width:400px;max-width:90vw">
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:20px">
<span style="font-weight:600;font-size:15px;color:var(--text)">Edit Project</span>
<button onclick="closeProjectEditModal()" style="background:none;border:none;color:var(--text-secondary);cursor:pointer;font-size:18px;padding:4px"></button>
</div>
<div style="margin-bottom:12px">
<label style="font-size:11px;color:var(--text-secondary);display:block;margin-bottom:4px">NAME</label>
<input id="editProjectName" style="width:100%;padding:10px 12px;background:var(--bg);border:1px solid var(--border2);border-radius:8px;color:var(--text);font-size:14px;box-sizing:border-box;outline:none">
</div>
<div style="margin-bottom:12px">
<label style="font-size:11px;color:var(--text-secondary);display:block;margin-bottom:4px">COLOR</label>
<div style="display:flex;gap:6px">
<button class="color-dot selected" data-color="#6366f1" onclick="selectProjectColor(this)" style="width:24px;height:24px;border-radius:50%;background:#6366f1;border:2px solid transparent;cursor:pointer"></button>
<button class="color-dot" data-color="#f59e0b" onclick="selectProjectColor(this)" style="width:24px;height:24px;border-radius:50%;background:#f59e0b;border:2px solid transparent;cursor:pointer"></button>
<button class="color-dot" data-color="#10b981" onclick="selectProjectColor(this)" style="width:24px;height:24px;border-radius:50%;background:#10b981;border:2px solid transparent;cursor:pointer"></button>
<button class="color-dot" data-color="#ef4444" onclick="selectProjectColor(this)" style="width:24px;height:24px;border-radius:50%;background:#ef4444;border:2px solid transparent;cursor:pointer"></button>
<button class="color-dot" data-color="#8b5cf6" onclick="selectProjectColor(this)" style="width:24px;height:24px;border-radius:50%;background:#8b5cf6;border:2px solid transparent;cursor:pointer"></button>
<button class="color-dot" data-color="#ec4899" onclick="selectProjectColor(this)" style="width:24px;height:24px;border-radius:50%;background:#ec4899;border:2px solid transparent;cursor:pointer"></button>
</div>
</div>
<div style="display:flex;gap:8px;justify-content:flex-end;margin-top:16px">
<button onclick="closeProjectEditModal()" style="padding:8px 16px;background:var(--bg);border:1px solid var(--border2);border-radius:8px;color:var(--text);cursor:pointer;font-size:13px">Cancel</button>
<button onclick="saveProjectEdit()" style="padding:8px 16px;background:var(--accent);border:none;border-radius:8px;color:#fff;cursor:pointer;font-size:13px;font-weight:500">Save</button>
</div>
</div>
</div>
</body>
</html>