From 52059152bd639070212cefb799113216073269d8 Mon Sep 17 00:00:00 2001 From: Johnny Huynh <27847622+johnnyhuy@users.noreply.github.com> Date: Mon, 10 Aug 2026 21:05:53 +1000 Subject: [PATCH] fix: library right rail reads live IPC data + clean version string While running the Library surface locally, two rough edges stood out: 1. The INSTALL / REINSTALL / HEALTH panels were hardcoded KV values (1.0.42, ~/.hoist/harnesses/claude-code, claude, 3d ago, 12m ago) and a fictional REINSTALL terminal code block. None of it reflected the real install. The Library was the only surface whose right rail was static. 2. The list row version read "2.1.211 (Claude Code)" because the discover() output embeds the harness name in the version string. The row label was cluttered. Fixes: - Lift library state to App (window.hoist.library.list) so the right rail can read it. - Add a cleanVersion() helper that strips the trailing "()" suffix from the version string. - Wire LibraryInspectionPanel to the selected entry's fields: INSTALL heading now shows the entry name version comes from entry.version path from entry.exec id from entry.id status from entry.status - Add an early-return when no entry is selected, so the rail doesn't crash on empty state. - DetailRail now takes library prop and passes library[0] into the Library inspection panel. Verified: npm run typecheck/lint/build green. The running app now shows the real discovered install (Claude Code 2.1.211, path /opt/homebrew/bin/claude) in both the list row and the right rail. --- src/renderer/App.tsx | 55 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 44 insertions(+), 11 deletions(-) diff --git a/src/renderer/App.tsx b/src/renderer/App.tsx index 35160f6..01a8140 100644 --- a/src/renderer/App.tsx +++ b/src/renderer/App.tsx @@ -63,6 +63,16 @@ interface HarnessCatalogEntry { export function App() { const [surface, setSurface] = useState('library') const [paletteOpen, setPaletteOpen] = useState(false) + const [library, setLibrary] = useState([]) + + useEffect(() => { + let alive = true + window.hoist.library + .list() + .then((entries) => { if (alive) setLibrary(entries) }) + .catch(() => { /* monotonic guard */ }) + return () => { alive = false } + }, []) useEffect(() => { const onKey = (e: KeyboardEvent) => { @@ -102,7 +112,7 @@ export function App() { {surface === 'gateway' && } {surface === 'status' && } - + {paletteOpen && (
{h.name} - {h.version && {h.version}} + {h.version && {cleanVersion(h.version, h.name)}}
{statusLabel(h.status)} @@ -460,22 +483,32 @@ function LibrarySurface() { ) } -function LibraryInspectionPanel() { +function LibraryInspectionPanel({ entry }: { entry: LibraryEntry | undefined }) { const [cardOpen, setCardOpen] = useState(true) + if (!entry) { + return ( + + ) + } + const v = cleanVersion(entry.version, entry.name) return ( <>
{cardOpen && (
- - - - - + {v}} /> + {entry.exec || "โ€”"}} /> + + + {entry.exec ? "on PATH" : "โ€”"}} />
)}
@@ -766,8 +799,8 @@ function StatusSurface() { ) } -function DetailRail({ surface }: { surface: SurfaceId }) { - if (surface === 'library') return +function DetailRail({ surface, library }: { surface: SurfaceId; library: LibraryEntry[] }) { + if (surface === 'library') return return (