fix(electrobun): address all 20 Codex review findings

CRITICAL:
- PTY leak: Terminal.svelte now calls pty.close on destroy, not just unsubscribe
- Agent session cleanup: clearSession() removes done/error sessions, backend
  deletes after 60s grace period

HIGH:
- Clone branch passthrough: user's branch name flows through callback
- Circular imports: extracted rpc.ts singleton, broke main.ts ↔ App.svelte cycle
- Settings wired to runtime: Terminal reads cursor/scrollback from settings
- Security disclaimer: added "prototype — not system keyring" notice
- ThemeEditor: fixed basePalette → initialPalette reference

MEDIUM:
- Clone race: UUID suffix instead of count-based index
- Silent failures: structured error returns from PTY handlers
- WebKitGTK mount: only current + previous group mounted
- Debug listeners: gated behind DEBUG, cleanup on destroy
- NDJSON residual buffer parsed on process exit
- Codex adapter: deduplicated tool_call/tool_result
- extraEnv: rejects CLAUDE*/CODEX*/OLLAMA* keys
- settings-db: runMigrations() with version tracking
- active_group: persisted via settings.set

LOW:
- Removed dead demo code, unused variables
- color-mix() fallbacks added
This commit is contained in:
Hibryda 2026-03-22 01:20:23 +01:00
parent ef0183de7f
commit 29a3370e79
18 changed files with 331 additions and 114 deletions

View file

@ -1,6 +1,6 @@
<script lang="ts">
import { onMount } from 'svelte';
import { appRpc } from '../main.ts';
import { appRpc } from '../rpc.ts';
type LogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error';

View file

@ -1,6 +1,6 @@
<script lang="ts">
import { onMount } from 'svelte';
import { appRpc } from '../main.ts';
import { appRpc } from '../rpc.ts';
import { PROVIDER_CAPABILITIES, type ProviderId } from '../provider-capabilities';
type PermMode = 'bypassPermissions' | 'default' | 'plan';

View file

@ -1,6 +1,6 @@
<script lang="ts">
import { onMount } from 'svelte';
import { appRpc } from '../main.ts';
import { appRpc } from '../rpc.ts';
import { THEMES, THEME_GROUPS, getPalette, type ThemeId, type ThemeMeta } from '../themes.ts';
import { themeStore } from '../theme-store.svelte.ts';
import { fontStore } from '../font-store.svelte.ts';

View file

@ -1,6 +1,6 @@
<script lang="ts">
import { onMount } from 'svelte';
import { appRpc } from '../main.ts';
import { appRpc } from '../rpc.ts';
interface CatalogPlugin {
id: string;

View file

@ -1,6 +1,6 @@
<script lang="ts">
import { onMount } from 'svelte';
import { appRpc } from '../main.ts';
import { appRpc } from '../rpc.ts';
type WakeStrategy = 'persistent' | 'on-demand' | 'smart';
type AnchorScale = 'small' | 'medium' | 'large' | 'full';

View file

@ -1,6 +1,6 @@
<script lang="ts">
import { onMount } from 'svelte';
import { appRpc } from '../main.ts';
import { appRpc } from '../rpc.ts';
import { PROVIDER_CAPABILITIES, type ProviderId } from '../provider-capabilities';
const ANCHOR_SCALES = ['small', 'medium', 'large', 'full'] as const;

View file

@ -1,6 +1,6 @@
<script lang="ts">
import { onMount } from 'svelte';
import { appRpc } from '../main.ts';
import { appRpc } from '../rpc.ts';
const KNOWN_KEYS: Record<string, string> = {
ANTHROPIC_API_KEY: 'Anthropic API Key',
@ -77,6 +77,11 @@
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div class="section" onclick={handleOutsideClick} onkeydown={e => e.key === 'Escape' && (keyDropOpen = false)}>
<div class="prototype-notice">
Prototype — secrets are stored locally in plain SQLite, not in the system keyring.
Do not store production credentials here.
</div>
<h3 class="sh">Keyring Status</h3>
<div class="keyring-status" class:ok={keyringAvailable} class:unavail={!keyringAvailable}>
<span class="ks-dot"></span>
@ -148,6 +153,15 @@
</div>
<style>
.prototype-notice {
padding: 0.5rem 0.625rem;
background: color-mix(in srgb, var(--ctp-peach) 12%, transparent);
border: 1px solid color-mix(in srgb, var(--ctp-peach) 30%, transparent);
border-radius: 0.25rem;
color: var(--ctp-peach);
font-size: 0.75rem;
line-height: 1.4;
}
.section { display: flex; flex-direction: column; gap: 0.5rem; }
.sh { margin: 0.375rem 0 0.125rem; font-size: 0.6875rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ctp-overlay0); }

View file

@ -1,5 +1,5 @@
<script lang="ts">
import { appRpc } from '../main.ts';
import { appRpc } from '../rpc.ts';
import { themeStore } from '../theme-store.svelte.ts';
import { CSS_VAR_MAP, getPalette, applyCssVars, type ThemePalette, type ThemeId } from '../themes.ts';
@ -98,7 +98,7 @@
const parsed = JSON.parse(text);
if (parsed.name) themeName = parsed.name;
if (parsed.palette && typeof parsed.palette === 'object') {
palette = { ...basePalette };
palette = { ...initialPalette };
for (const [k, v] of Object.entries(parsed.palette)) {
if (k in palette && typeof v === 'string') {
(palette as unknown as Record<string, string>)[k] = v;