fix: full review pass (main process, voice pipeline, Hermes client, HUD) and e2e-validated local voice (v2.1.0.1)

Electron main
- utility-process channel: sherpa output copied into V8 buffers (Electron rejects external
  buffers), audio exchanged as base64; worker restart on timeout, identity-safe exit handling,
  deterministic native unload by restart
- webhook: loopback by default without secret, UTF-8-safe body assembly, clean restart, port validation
- files IPC: realpath-based root check, openPath allow-list (reveal-only outside document folders),
  Windows reserved names; store: debounced async atomic writes with backup of corrupt files;
  logger: streaming writes with rotation; log message size cap
- HTTP stream proxy: socket released on idle timeout / renderer destroyed, id validation
- model manager: inactivity timeout, retrying rm/rename (Windows locks), engine stopped before
  replacing a model; WAV decoder handles float/24-bit; IPC payload validation
- window: opaque rounded window on Windows, navigation lock-down, visibility events;
  Ctrl+Alt+Escape instead of the Task Manager shortcut; single-instance guard; EVEFLOW_USER_DATA

Voice pipeline
- abort semantics (SendHandle.aborted), abort before the stream opens, session id prefixes per transport
- hands-free re-arm after replies without speech, start/stop race, no chime on auto re-arm,
  no silence shipped to STT (400 ms pre-roll), no transcription of empty manual stops
- TTS: bounded prefetch, cancellable segments, non-interrupting notices, volume applied at play time
- SSE CRLF split, usage in chat completions, finish_reason length, phonetic regex hoisted

HUD
- core renderer: no canvas shadows, cached colours, reusable spectrum buffer, theme read on change,
  30 fps idle, stops when the window is hidden; ping flashes on send / tool / speech
- deltas coalesced per animation frame; stable auto-scroll; narrow selectors everywhere
- bundled fonts (offline), reduce-motion fix, error toasts, ops drawer below 1180 px,
  interim transcript and first-token latency in the core caption, Ctrl+K, dialog semantics,
  switch/aria roles, compact widget cleanup, Whisper small recommended for French
- docs/ROADMAP.md: audit results, e2e results and the plan towards a real JARVIS

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Wn5VX9HNbJ7N54hR24u9Y
This commit is contained in:
Claude committed 2026-09-03 18:08:09 +00:00
1 parent b1b8d0d5d4
commit 5f0fa7a1e2
55 files changed
+1181 -433

No files matched your search

+54 -8
View File
@@ -7,6 +7,7 @@
grid-template-rows: 46px 1fr;
border-radius: 14px;
overflow: hidden;
background-clip: padding-box;
background:
radial-gradient(1200px 700px at 50% 40%, rgba(var(--accent-rgb), 0.08), transparent 60%),
linear-gradient(180deg, var(--bg-1) 0%, var(--bg-0) 100%);
@@ -51,6 +52,17 @@
grid-template-columns: minmax(340px, 1fr) minmax(380px, 1fr);
}
.hud-body > .ops-column {
position: absolute;
right: 14px;
top: 12px;
bottom: 14px;
width: min(360px, 60%);
z-index: 6;
background: var(--bg-1);
border-radius: var(--radius);
box-shadow: -20px 0 60px rgba(0, 0, 0, 0.5);
}
.hud-body > .ops-column:not(.open) {
display: none;
}
}
@@ -68,7 +80,6 @@
background: var(--panel);
border: 1px solid var(--line);
border-radius: var(--radius);
backdrop-filter: blur(14px);
display: flex;
flex-direction: column;
min-height: 0;
@@ -310,7 +321,8 @@
background: linear-gradient(180deg, rgba(var(--accent-rgb), 0.06), transparent);
-webkit-app-region: drag;
}
.topbar > * {
.topbar button,
.topbar .chip {
-webkit-app-region: no-drag;
}
.topbar .brand {
@@ -346,9 +358,6 @@
overflow: hidden;
-webkit-app-region: drag;
}
.topbar .status-strip > * {
-webkit-app-region: no-drag;
}
.topbar .clock {
font-family: var(--font-mono);
font-size: 13px;
@@ -421,6 +430,21 @@
.core-state.success {
color: var(--success);
}
.core-interim {
font-family: var(--font-ui);
font-size: 15px;
color: var(--ink-1);
max-width: 82%;
text-align: center;
opacity: 0.85;
min-height: 1.4em;
}
.core-latency {
font-family: var(--font-mono);
font-size: 10px;
letter-spacing: 0.2em;
color: var(--ink-3);
}
.core-sub {
font-family: var(--font-mono);
font-size: 12px;
@@ -438,10 +462,13 @@
right: 0;
text-align: center;
font-family: var(--font-display);
font-size: 22px;
font-size: clamp(13px, 2.2vw, 22px);
font-weight: 900;
letter-spacing: 0.5em;
padding-left: 0.5em;
letter-spacing: clamp(0.15em, 0.8vw, 0.5em);
padding: 0 12px 0 calc(12px + 0.4em);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
color: var(--ink-0);
text-shadow: 0 0 22px var(--accent-glow);
pointer-events: none;
@@ -474,6 +501,25 @@
margin-left: auto;
}
/* ── Toasts ────────────────────────────────────────────────────────────── */
.toast-stack {
position: absolute;
left: 50%;
bottom: 22px;
transform: translateX(-50%);
z-index: 18;
display: flex;
flex-direction: column;
gap: 8px;
width: min(560px, 80%);
pointer-events: none;
}
.toast-stack .error-banner {
pointer-events: auto;
box-shadow: 0 20px 50px rgba(0, 0, 0, 0.5);
animation: rise-in 200ms ease-out;
}
/* ── Overlay / modal ───────────────────────────────────────────────────── */
.overlay {
position: absolute;