feat(electrobun): wire EVERYTHING — all settings persist, theme editor, marketplace

All settings wired to SQLite persistence:
- AgentSettings: shell, CWD, permissions, providers (JSON blob)
- SecuritySettings: branch policies (JSON array)
- ProjectSettings: per-project via setProject RPC
- OrchestrationSettings: wake, anchors, notifications
- AdvancedSettings: logging, OTLP, plugins, import/export JSON

Theme Editor:
- 26 color pickers (14 Accents + 12 Neutrals)
- Live CSS var preview as you pick colors
- Save custom theme to SQLite, cancel reverts
- Import/export theme as JSON
- Custom themes in dropdown with delete button

Extensions Marketplace:
- 8-plugin demo catalog (Browse/Installed tabs)
- Search/filter by name or tag
- Install/uninstall with SQLite persistence
- Plugin cards with emoji icons, tags, version

Terminal font hot-swap:
- fontStore.onTermFontChange() → xterm.js options update + fitAddon.fit()
- Resize notification to PTY daemon after font change

All 7 settings categories functional. Every control persists and takes effect.
This commit is contained in:
Hibryda 2026-03-20 05:45:10 +01:00
parent 6002a379e4
commit 5032021915
20 changed files with 1005 additions and 271 deletions

View file

@ -1,4 +1,7 @@
<script lang="ts">
import { onMount } from 'svelte';
import { appRpc } from '../main.ts';
const KNOWN_KEYS: Record<string, string> = {
ANTHROPIC_API_KEY: 'Anthropic API Key',
OPENAI_API_KEY: 'OpenAI API Key',
@ -16,10 +19,7 @@
let keyDropOpen = $state(false);
let saving = $state(false);
interface BranchPolicy {
pattern: string;
action: 'block' | 'warn';
}
interface BranchPolicy { pattern: string; action: 'block' | 'warn'; }
let branchPolicies = $state<BranchPolicy[]>([
{ pattern: 'main', action: 'block' },
{ pattern: 'prod*', action: 'warn' },
@ -30,6 +30,10 @@
let availableKeys = $derived(Object.keys(KNOWN_KEYS).filter(k => !storedKeys.includes(k)));
let newKeyLabel = $derived(newKey ? (KNOWN_KEYS[newKey] ?? newKey) : 'Select key...');
function persistPolicies() {
appRpc?.request['settings.set']({ key: 'branch_policies', value: JSON.stringify(branchPolicies) }).catch(console.error);
}
function handleSaveSecret() {
if (!newKey || !newValue) return;
saving = true;
@ -49,15 +53,25 @@
if (!newPattern.trim()) return;
branchPolicies = [...branchPolicies, { pattern: newPattern.trim(), action: newAction }];
newPattern = ''; newAction = 'warn';
persistPolicies();
}
function removeBranchPolicy(idx: number) {
branchPolicies = branchPolicies.filter((_, i) => i !== idx);
persistPolicies();
}
function handleOutsideClick(e: MouseEvent) {
if (!(e.target as HTMLElement).closest('.dd-wrap')) keyDropOpen = false;
}
onMount(async () => {
if (!appRpc) return;
const res = await appRpc.request['settings.get']({ key: 'branch_policies' }).catch(() => ({ value: null }));
if (res.value) {
try { branchPolicies = JSON.parse(res.value); } catch { /* ignore */ }
}
});
</script>
<!-- svelte-ignore a11y_no_static_element_interactions -->