- Tauri 2.0 + SvelteKit Projekt aufgesetzt - Basis-UI mit 3 Panels (Chat, Aktivität, Präsentation) - Roter STOPP-Button Footer - Autonomes Gedächtnis-System (memory.rs) - Änderungs-Log / Audit Trail (audit.rs) - Multi-Agent-View Komponenten - NixOS Entwicklungsumgebung (shell.nix) Phase 1 abgeschlossen, Claude SDK Integration folgt. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
241 lines
4.4 KiB
Svelte
241 lines
4.4 KiB
Svelte
<script lang="ts">
|
|
import { onMount } from 'svelte';
|
|
|
|
interface MemoryStats {
|
|
total: number;
|
|
sticky: number;
|
|
by_category: Record<string, number>;
|
|
}
|
|
|
|
let stats: MemoryStats = {
|
|
total: 0,
|
|
sticky: 0,
|
|
by_category: {}
|
|
};
|
|
|
|
let lastSync = 'Noch nie';
|
|
let loading = true;
|
|
|
|
// Kategorien mit Icons
|
|
const categoryIcons: Record<string, string> = {
|
|
Critical: '🔑',
|
|
Pattern: '📋',
|
|
Preference: '⚙️',
|
|
GuardRail: '🛡️',
|
|
Hook: '🪝',
|
|
Skill: '🎯',
|
|
MCP: '🔌'
|
|
};
|
|
|
|
onMount(async () => {
|
|
// TODO: Echte Daten laden via Tauri
|
|
// const result = await invoke('load_memory');
|
|
|
|
// Placeholder-Daten
|
|
stats = {
|
|
total: 95,
|
|
sticky: 23,
|
|
by_category: {
|
|
Critical: 8,
|
|
Pattern: 47,
|
|
Preference: 12,
|
|
GuardRail: 15,
|
|
Hook: 5,
|
|
Skill: 8
|
|
}
|
|
};
|
|
lastSync = 'vor 2 Minuten';
|
|
loading = false;
|
|
});
|
|
|
|
async function syncNow() {
|
|
loading = true;
|
|
// TODO: Mit claude-db synchronisieren
|
|
await new Promise((r) => setTimeout(r, 1000));
|
|
lastSync = 'gerade eben';
|
|
loading = false;
|
|
}
|
|
</script>
|
|
|
|
<div class="memory-panel">
|
|
<div class="panel-header">
|
|
<h2>🧠 Gedächtnis-System</h2>
|
|
<span class="sync-status">
|
|
{#if loading}
|
|
<span class="loading">Synchronisiere...</span>
|
|
{:else}
|
|
Letzter Sync: {lastSync}
|
|
{/if}
|
|
</span>
|
|
</div>
|
|
|
|
<div class="stats-summary">
|
|
<div class="stat-item">
|
|
<span class="stat-value">{stats.total}</span>
|
|
<span class="stat-label">Einträge gesamt</span>
|
|
</div>
|
|
<div class="stat-item sticky">
|
|
<span class="stat-value">{stats.sticky}</span>
|
|
<span class="stat-label">Sticky (nie vergessen)</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="category-list">
|
|
<h3>📥 Automatisch geladen:</h3>
|
|
{#each Object.entries(stats.by_category) as [category, count]}
|
|
<div class="category-item">
|
|
<span class="category-icon">{categoryIcons[category] || '📦'}</span>
|
|
<span class="category-name">{category}</span>
|
|
<span class="category-count">{count}</span>
|
|
</div>
|
|
{/each}
|
|
</div>
|
|
|
|
<div class="actions">
|
|
<button class="btn-sync" on:click={syncNow} disabled={loading}>
|
|
🔄 Jetzt synchronisieren
|
|
</button>
|
|
<button class="btn-settings">
|
|
⚙️ Einstellungen
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<style>
|
|
.memory-panel {
|
|
padding: var(--spacing-md);
|
|
height: 100%;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.panel-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: var(--spacing-md);
|
|
}
|
|
|
|
.panel-header h2 {
|
|
font-size: 1rem;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.sync-status {
|
|
font-size: 0.75rem;
|
|
color: var(--text-secondary);
|
|
}
|
|
|
|
.loading {
|
|
color: var(--accent);
|
|
animation: pulse 1s ease-in-out infinite;
|
|
}
|
|
|
|
.stats-summary {
|
|
display: flex;
|
|
gap: var(--spacing-md);
|
|
margin-bottom: var(--spacing-md);
|
|
}
|
|
|
|
.stat-item {
|
|
flex: 1;
|
|
padding: var(--spacing-md);
|
|
background: var(--bg-secondary);
|
|
border-radius: var(--radius-md);
|
|
text-align: center;
|
|
}
|
|
|
|
.stat-item.sticky {
|
|
border: 1px solid var(--success);
|
|
}
|
|
|
|
.stat-value {
|
|
display: block;
|
|
font-size: 1.5rem;
|
|
font-weight: 700;
|
|
color: var(--text-primary);
|
|
}
|
|
|
|
.stat-label {
|
|
font-size: 0.75rem;
|
|
color: var(--text-secondary);
|
|
}
|
|
|
|
.category-list {
|
|
flex: 1;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
.category-list h3 {
|
|
font-size: 0.875rem;
|
|
margin-bottom: var(--spacing-sm);
|
|
color: var(--text-secondary);
|
|
}
|
|
|
|
.category-item {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--spacing-sm);
|
|
padding: var(--spacing-xs) var(--spacing-sm);
|
|
border-radius: var(--radius-sm);
|
|
transition: background 0.2s ease;
|
|
}
|
|
|
|
.category-item:hover {
|
|
background: var(--bg-secondary);
|
|
}
|
|
|
|
.category-icon {
|
|
width: 24px;
|
|
text-align: center;
|
|
}
|
|
|
|
.category-name {
|
|
flex: 1;
|
|
font-size: 0.875rem;
|
|
}
|
|
|
|
.category-count {
|
|
font-size: 0.875rem;
|
|
font-weight: 600;
|
|
color: var(--accent);
|
|
}
|
|
|
|
.actions {
|
|
display: flex;
|
|
gap: var(--spacing-sm);
|
|
margin-top: var(--spacing-md);
|
|
}
|
|
|
|
.actions button {
|
|
flex: 1;
|
|
padding: var(--spacing-sm) var(--spacing-md);
|
|
border-radius: var(--radius-md);
|
|
font-size: 0.875rem;
|
|
font-weight: 500;
|
|
transition: all 0.2s ease;
|
|
}
|
|
|
|
.btn-sync {
|
|
background: var(--accent);
|
|
color: white;
|
|
}
|
|
|
|
.btn-sync:hover:not(:disabled) {
|
|
background: var(--accent-hover);
|
|
}
|
|
|
|
.btn-sync:disabled {
|
|
background: var(--bg-tertiary);
|
|
color: var(--text-secondary);
|
|
}
|
|
|
|
.btn-settings {
|
|
background: var(--bg-secondary);
|
|
border: 1px solid var(--bg-tertiary);
|
|
}
|
|
|
|
.btn-settings:hover {
|
|
background: var(--bg-tertiary);
|
|
}
|
|
</style>
|