feat(electrobun): fixes + 7 new features (terminal input, file browser, memory, toasts)
Fixes: - Terminal accepts keyboard input (echo mode with prompt) - Terminal drawer collapses properly (display:none preserves xterm state) Features: - 6 project tabs: Model | Docs | Context | Files | SSH | Memory - FileBrowser.svelte: recursive tree with expand/collapse + file preview - MemoryTab.svelte: memory cards with trust badges (human/agent/auto) - Subagent tree in AgentPane (demo: search-agent, test-runner) - Drag resize handle between agent pane and terminal - Theme dropdown in Settings (4 Catppuccin flavors) - ToastContainer.svelte: auto-dismiss notifications
This commit is contained in:
parent
b11a856b72
commit
4ae558af17
14 changed files with 1168 additions and 196 deletions
208
ui-electrobun/src/mainview/MemoryTab.svelte
Normal file
208
ui-electrobun/src/mainview/MemoryTab.svelte
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
<script lang="ts">
|
||||
type TrustLevel = 'human' | 'agent' | 'auto';
|
||||
|
||||
interface MemoryFragment {
|
||||
id: number;
|
||||
title: string;
|
||||
body: string;
|
||||
tags: string[];
|
||||
trust: TrustLevel;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
const MEMORIES: MemoryFragment[] = [
|
||||
{
|
||||
id: 1,
|
||||
title: 'Agent Orchestrator — Tech Stack',
|
||||
body: 'Tauri 2.x + Svelte 5 frontend. Rust backend with rusqlite (WAL mode). Agent sessions via @anthropic-ai/claude-agent-sdk query(). Sidecar uses stdio NDJSON.',
|
||||
tags: ['agor', 'tech-stack', 'architecture'],
|
||||
trust: 'human',
|
||||
updatedAt: '2026-03-20',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: 'btmsg SQLite conventions',
|
||||
body: 'All queries use named column access (row.get("column_name")) — never positional indices. Rust structs use #[serde(rename_all = "camelCase")].',
|
||||
tags: ['agor', 'database', 'btmsg'],
|
||||
trust: 'agent',
|
||||
updatedAt: '2026-03-19',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: 'Wake Scheduler — 3 strategies',
|
||||
body: 'persistent=resume prompt, on-demand=fresh session, smart=threshold-gated on-demand. 6 wake signals from S-3 hybrid tribunal. Pure scorer in wake-scorer.ts (24 tests).',
|
||||
tags: ['agor', 'wake-scheduler', 'agents'],
|
||||
trust: 'agent',
|
||||
updatedAt: '2026-03-18',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
title: 'Svelte 5 runes file extension rule',
|
||||
body: 'Store files using Svelte 5 runes ($state, $derived) MUST have .svelte.ts extension. Plain .ts compiles but fails at runtime with "rune_outside_svelte".',
|
||||
tags: ['agor', 'svelte', 'conventions'],
|
||||
trust: 'auto',
|
||||
updatedAt: '2026-03-17',
|
||||
},
|
||||
];
|
||||
|
||||
const TRUST_LABELS: Record<TrustLevel, string> = {
|
||||
human: 'Human',
|
||||
agent: 'Agent',
|
||||
auto: 'Auto',
|
||||
};
|
||||
</script>
|
||||
|
||||
<div class="memory-tab">
|
||||
<div class="memory-header">
|
||||
<span class="memory-count">{MEMORIES.length} fragments</span>
|
||||
<span class="memory-hint">via Memora</span>
|
||||
</div>
|
||||
|
||||
<div class="memory-list">
|
||||
{#each MEMORIES as mem (mem.id)}
|
||||
<article class="memory-card">
|
||||
<div class="memory-card-top">
|
||||
<span class="memory-title">{mem.title}</span>
|
||||
<span class="trust-badge trust-{mem.trust}" title="Source: {TRUST_LABELS[mem.trust]}">
|
||||
{TRUST_LABELS[mem.trust]}
|
||||
</span>
|
||||
</div>
|
||||
<p class="memory-body">{mem.body}</p>
|
||||
<div class="memory-footer">
|
||||
<div class="memory-tags">
|
||||
{#each mem.tags as tag}
|
||||
<span class="tag">{tag}</span>
|
||||
{/each}
|
||||
</div>
|
||||
<span class="memory-date">{mem.updatedAt}</span>
|
||||
</div>
|
||||
</article>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.memory-tab {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.memory-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0.375rem 0.625rem;
|
||||
border-bottom: 1px solid var(--ctp-surface0);
|
||||
background: var(--ctp-mantle);
|
||||
flex-shrink: 0;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.memory-count { color: var(--ctp-text); font-weight: 500; }
|
||||
.memory-hint { color: var(--ctp-overlay0); font-style: italic; }
|
||||
|
||||
.memory-list {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 0.375rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.375rem;
|
||||
}
|
||||
|
||||
.memory-list::-webkit-scrollbar { width: 0.25rem; }
|
||||
.memory-list::-webkit-scrollbar-track { background: transparent; }
|
||||
.memory-list::-webkit-scrollbar-thumb { background: var(--ctp-surface1); border-radius: 0.25rem; }
|
||||
|
||||
.memory-card {
|
||||
background: var(--ctp-surface0);
|
||||
border: 1px solid var(--ctp-surface1);
|
||||
border-radius: 0.375rem;
|
||||
padding: 0.5rem 0.625rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.3rem;
|
||||
transition: border-color 0.12s;
|
||||
}
|
||||
|
||||
.memory-card:hover { border-color: var(--ctp-surface2); }
|
||||
|
||||
.memory-card-top {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.memory-title {
|
||||
flex: 1;
|
||||
font-size: 0.8125rem;
|
||||
font-weight: 600;
|
||||
color: var(--ctp-text);
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.trust-badge {
|
||||
flex-shrink: 0;
|
||||
padding: 0.1rem 0.35rem;
|
||||
border-radius: 0.25rem;
|
||||
font-size: 0.6rem;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.04em;
|
||||
}
|
||||
|
||||
.trust-human {
|
||||
background: color-mix(in srgb, var(--ctp-green) 15%, transparent);
|
||||
color: var(--ctp-green);
|
||||
}
|
||||
|
||||
.trust-agent {
|
||||
background: color-mix(in srgb, var(--ctp-blue) 15%, transparent);
|
||||
color: var(--ctp-blue);
|
||||
}
|
||||
|
||||
.trust-auto {
|
||||
background: color-mix(in srgb, var(--ctp-overlay1) 15%, transparent);
|
||||
color: var(--ctp-overlay1);
|
||||
}
|
||||
|
||||
.memory-body {
|
||||
margin: 0;
|
||||
font-size: 0.75rem;
|
||||
color: var(--ctp-subtext1);
|
||||
line-height: 1.45;
|
||||
font-family: var(--ui-font-family);
|
||||
}
|
||||
|
||||
.memory-footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
margin-top: 0.1rem;
|
||||
}
|
||||
|
||||
.memory-tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.25rem;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.tag {
|
||||
padding: 0.05rem 0.3rem;
|
||||
background: var(--ctp-surface1);
|
||||
border-radius: 0.2rem;
|
||||
font-size: 0.625rem;
|
||||
color: var(--ctp-overlay1);
|
||||
font-family: var(--term-font-family);
|
||||
}
|
||||
|
||||
.memory-date {
|
||||
font-size: 0.625rem;
|
||||
color: var(--ctp-overlay0);
|
||||
white-space: nowrap;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
</style>
|
||||
Loading…
Add table
Add a link
Reference in a new issue