Repository navigation
v2.3.0
Added
-
Agents: define your own tools. A new Settings screen (
⌘,on macOS, also
under File ▸ Settings… and in the command palette;Ctrl+,or the
command palette elsewhere) lets you add custom
agents with a name, command line, and color — for example aclaude-lite
that runsclaude --model haiku. Custom agents appear in the⌘Tlauncher
alongside the built-ins, with the same PATH availability check, and persist
and revive across restarts. Definitions live inagents.jsonin the Hive
state directory and can be hand-edited. Built-in agent ids cannot be
redefined, and custom agents do not support conversation resume — Restart
re-runs their command rather than continuing the prior session. -
GUI:
⌘Bjumps to the next session that rang the bell (the pulsing
ones), cycling through them and wrapping — no more hunting for the
flashing row with the mouse.⇧⌘Bjumps back to the session you were
working in before the first⌘B— so a round of bells can bounce you
through several sessions and one keystroke still returns you to the
work you interrupted. A minimized session that rings its bell is
restored on the way in and returned to the tray on the way back. Both are in the ⌘/ help overlay, the
command palette, and the macOS Session menu (Ctrl+B/Ctrl+Shift+B
on Windows and Linux). -
Agents: Pi (
@earendil-works/pi-coding-agent) is now
a launchable agent. Hive pins each session's id viapi --session-id, so
Restart resumes the exact conversation by id — unambiguous even when
sibling sessions share a worktree (same guarantee as Claude/Gemini). -
GUI: keyboard-shortcuts help overlay on
⌘/, listing every binding —
including the ones no menu shows (terminal-levelCtrl+Shift+C/V/A
copy/paste/select-all,⇧↩newline, launcher digit keys, sidebar
resizer keys). Also reachable from the command palette ("Keyboard
Shortcuts") and the macOS Help menu. The palette's shortcut column
and the overlay render from one shared table (lib/shortcuts.js)
so they cannot drift, and non-mac platforms now seeCtrl+-style
hints instead of mac glyphs. -
GUI: actionable empty states. First run shows "No sessions yet" with
a New session button; an empty project and an all-minimized grid get
their own hints — replacing the bare CSS placeholder text (or a
fully blank pane in single mode). -
GUI: sidebar project collapse state persists across launches
(localStorage,hive.collapsedProjects; pruned when projects are
deleted). -
GUI: the agent launcher opens instantly with a "Loading agents…" row
(then "No agents found" when the list is empty) instead of popping
in fully-formed a beat after the keypress; creating a session
flashes "creating session…" in the status bar. -
GUI: accessibility pass — the sidebar footer hint no longer claims
the palette is on ⌘K (it is ⇧⌘K); project collapse carets are real
buttons witharia-expandedand keyboard focus rings; the dead
session overlay is analertdialog; palette input, tile headers,
and tray chips carry aria-labels; keyboard-focus rings on sidebar,
tile, tray, and banner controls. -
GUI: minimize sessions to hide them from grid views. Each tile in
the project-grid and all-sessions-grid now has a small minimize
button on the right of its header (–). Minimized sessions are
removed from the grid and appear as chips in a tray below the
terminals; clicking a chip restores the session to the grid and
switches to it. Minimized sessions stay alive (output keeps
buffering) and remain reachable in single-session mode via the
sidebar, command palette, and⌘[/]cycling. State is per-app-run
(not persisted across launches). (#202) -
Frontend test harness.
scripts/test.shruns four layers: Go
(existing), Vitest unit tests for the newcmd/hivegui/frontend/src/lib/
pure modules, jsdom DOM tests, and a Playwright E2E suite that
drives the GUI through an in-browser Wails-mock bridge
(test/e2e/wails-mock.js). Grid layout math (computeGridDims,
buildGridLayout,computeSpatialMove), the visibility gate for
xtermfit(), the snake/camel wire normalizer, and the
cross-platformcmdOrCtrlhelper are now covered as pure
functions — the regression classes behind the recent ctrl-arrow,
grid-mode-revert, and canvas-resize bugs all have direct unit
tests. Linux CI runs every layer on every PR. -
Daemon integration tests covering update/restart/resize and
multi-control-conn broadcast fan-out. -
GUI: last view (single / grid-project / grid-all) persists across
launches. Previously the GUI always booted into single-focus mode
regardless of how it was left; now it restores the mode you last
used. Stored inlocalStorageunderhive.view. (#187)
Changed
- GUI:
Ctrl+?now opens the keyboard-shortcuts panel on Windows and
Linux, alongside the existingCtrl+/. macOS already accepted both
⌘?and⌘/via the Help menu item; those platforms have no native
menu, so onlyCtrl+/worked there. - GUI: the sidebar footer now shows the running version and build of
hiveandhivedinstead of the keyboard-shortcut hints. It shows a
single line when both binaries come from the same build, and expands
to one line each — highlighted — when they differ, making a stale
daemon visible at a glance rather than only via the restart banner.
The shortcut hints are still available via the command palette
(⇧⌘K) and the keyboard-shortcuts overlay (⌘/). - GUI: the Debug menu is relabeled "Toggle Debug Trace" / "Copy Debug
Trace" (was "Scroll Debug" / "Scroll Trace"); the captured trace now
covers grid relayout, focus, keydown routing, a main-thread heartbeat,
and inbound daemon traffic — not just scrolling.
Fixed
-
GUI: "Restart Hive" now actually replaces the daemon — or says why it
can't. It askshivedto exit over the control connection Hive
already holds, then confirms the socket has gone quiet before
relaunching, so the new window can no longer come back attached to
the daemon it was supposed to replace (the stale-build banner
returning immediately after a "restart" was this bug). Signalling the
pid recorded in<sock>.pidremains as a fallback, but the pidfile is
no longer trusted as proof: three of its paths could report success
having killed nothing. If the daemon survives both attempts, the
restart fails visibly in the banner instead of quitting into a broken
state. Restarts are also no longer stalled ~5s by a liveness check
that could never observe the daemon exiting. -
GUI:
hivedexiting no longer deletes a newer daemon's pidfile,
which left Restart Hive with no handle on the running daemon at all. -
GUI: Restart Hive… is now in the File menu and the command
palette. It was previously reachable only from the daemon-stale
banner, so when the GUI and daemon builds matched there was no way to
restart Hive from inside the app. -
GUI: errors are written to
hivegui.login the Hive state directory,
next tohived.log. Under LaunchServices the GUI's stderr goes to
/dev/null, so failures previously left no trace anywhere on disk. -
GUI: renaming a session from its tile header no longer throws a
ReferenceErrorand silently discards the new name. The tile
rename's commit handler calledUpdateSessionwithout it being
imported, so the rename input closed but the daemon call never
fired. -
GUI: full-screen agent sessions (claude/codex/pi and other alternate-
screen TUIs) no longer freeze for seconds on resize or a single↔grid
toggle. Such a resize requested a full scrollback replay — the daemon
re-streams its entire raw byte ring (toward an 8 MB cap on a long-lived
session) and the GUI parsed it in one synchronous write — but the
alternate screen has no user-facing scrollback and the program repaints
itself from SIGWINCH, so the replay was pure cost. It is now skipped on
the alternate screen; normal-buffer (shell) sessions still replay. -
GUI: scrollback replays no longer destroy the reading position
("scrolling jumps around with codex"). When a window resize, sidebar
drag, or grid reflow triggered a scrollback replay while the user
was scrolled up reading history, the replay's buffer reset dumped
them at the bottom — the #213 don't-snap flag only suppressed the
final explicit snap, after the position was already gone. The replay
now captures the reader's distance from the bottom before the wipe
and restores it once the replay has fully parsed. The reset and the
final viewport placement are also parse-ordered now (xterm's write
queue is async), so under codex-rate output a replay can no longer
interleave with unparsed live bytes and paint duplicated lines.
Deliberate mode switches still snap to the bottom. Adds a scroll
tracer (localStorage hive.debug = '1', dump
window.__hive_scrolltrace) for field diagnosis, and a real-daemon
e2e suite (scroll-codex.spec.js) that reproduces the bug on the
old code and locks the invariants. -
GUI: action failures are no longer silent. Copying/pasting inside a
terminal, creating/duplicating/restarting/closing a session, renaming
or recoloring or reordering sessions and projects, saving a project,
and opening the agent launcher now show an error in the status bar
when the underlying daemon call fails (e.g. connection lost) —
previously the click just did nothing, with no trace. Status-bar
errors are guaranteed a minimum visibility window (1.5s), pulse red,
auto-hide (errors 6s, info 2.5s), revert to the persistent status
("connected" / session name) instead of going blank, and are
announced to screen readers (role="status",aria-live="polite").
Also fixed: opening the launcher when its sidebar anchor row isn't in
the DOM could throw and leave the launcher unopened with no feedback. -
GUI: Enter now commits and Escape now cancels inline renames (session
rows, project rows, and tile headers). A capture-phase
stopPropagation()listener on the rename input was cancelling the
same input's bubble-phase Enter/Escape handler (DOM dispatch skips
the bubble invocation once the stop-propagation flag is set), so
Enter did nothing and Escape couldn't cancel — the rename only ever
committed when the input lost focus, including after an attempted
Escape. The handlers now live in the single capture-phase listener. -
Daemon diagnosability hardening: failures that were previously
swallowed are now logged. Registry metadata-persist failures (12
sites — session/project entries and order indexes) warn with the
operation that lost the write; dropping a slow session/project event
listener warns instead of silently desyncing the GUI (and the event
buffers grew 16→64 so a many-session reorder can't overflow a
healthy listener); pidfile cleanup failures are logged at shutdown.
Worktree creation failures now report every attempted strategy
(joined errors instead of last-attempt-only), and existing-branch
detection usesgit rev-parseexit codes instead of matching git's
locale-dependent error text. Thehived-ws-bridgetest shim rejects
malformed JSON-RPC params instead of running handlers on zeroed
structs, and serializes concurrent frame writes per daemon
connection so racing writers can't corrupt the wire stream. -
GUI: keystrokes typed immediately after switching to a grid view are no
longer dropped. Switching to grid reparents the active tile and triggers
async resize/fit on neighbour tiles, both of which momentarily blurred the
active terminal to<body>; a character typed in that sub-frame gap was
silently lost (e.g.hello→ello). A synchronous focus guard now
reclaims the terminal the instant it blurs during the post-switch settle
window, and the focus-retry loop no longer re-focuses an already-focused
textarea (which cleared pending input). (#186) -
GUI:
Shift+Enterin an agent session now inserts a newline instead
of submitting, so you can compose multi-line prompts for Claude/Codex.
xterm sends a bare\rforShift+Enterand drops the Shift, so the
agents couldn't distinguish it from plain Enter and submitted. The
custom key handler now interceptsShift+Enterand writes Ctrl+J
(\x0a) — the newline byte both agents accept with no terminal
configuration. Plain Enter still submits;⌘/Ctrl+Enterstill toggles
grid-project view. Works on all platforms. (#217) -
GUI: scrolling discipline on mode switch and resize. Switching
display modes (focused / grid / grid-project) now always snaps
every visible tile to the bottom — mode toggles are deliberate
user actions, so the previous "land wherever the buffer happened
to be" behavior is gone. Resize keeps the existing 2-line
sticky-bottom tolerance (#163). The viewport is never automatically
moved away from where the user has placed it: when a window resize
triggers a scrollback replay while the user is reading deliberate
scrollback, the replay no longer yanks them to the bottom on
completion. (#213) -
GUI: three grid-mode regressions and lock-in tests. (1) The first
time entering grid mode after restart no longer mis-anchors the
scrollback replay baseline against xterm's 80-column default,
preventing repeated spurious replays as DPR/fit jitter crosses the
threshold. (2) Minimizing or restoring a session no longer triggers
spurious scrollback replays in the remaining tiles when their
column widths reflow. (3) After resizing the window, toggling the
sidebar with⌘Sno longer strands keystrokes ondocument.body
— the keyboard handler now routes throughtoggleSidebar()and
the toggle re-asserts keyboard focus the same waysetViewdoes
after grid/single transitions. Adds unit coverage for the rebaseline
helper (applyRebaseline) and Playwright e2e regressions for all
three (plus an R-control case asserting that legitimate window-resize
replays still fire). (#208) -
GUI: scrollback no longer renders at the narrow grid width after a
single → grid → single transition, and live output no longer
overwrites already-scrolled lines. The daemon now keeps a per-session
raw-byte ring buffer (8 MiB) and re-streams it through a new
REQUEST_REPLAYwire frame whenever the GUI's column count changes
by ≥4 cols; the frontendterm.reset()s on ascrollback_replay_begin
event so the replay paints onto a clean buffer. Initial attach uses
the same path, so reattach scrollback is no longer capped at the old
500-row vt10x history. (#200) -
Worktrees: surface a log warning when
git fetch originfails or
origin/HEADis not configured, instead of silently falling back to
local HEAD (or worse, silently basing a new worktree on a stale
cachedorigin/HEAD). Closes the spec gap in #192's "remote
unreachable" success criterion. -
Worktrees now branch from
origin/<default-branch>(typically
origin/main) instead of local HEAD. Previously, creating a
session-backed worktree from a stale checkout produced a worktree
on outdated code, wasting agent work on rebases and rediscovering
already-fixed bugs.internal/worktree.CreateWorktreeperforms a
best-effortgit fetch originand resolves
refs/remotes/origin/HEADbeforegit worktree add. Repos with no
remote, offline environments, or unreachable upstreams fall back to
HEAD-based branching transparently. (#192) -
GUI: switching from single-focus mode to grid mode no longer leaves
the active session visually highlighted but unable to receive
keystrokes (regression of #181). Single → grid is the only transition
that fires a synchronousdisplay:noneflip on the active tile
duringrenderGrid's parent class swap, which blurs the xterm
helper-textarea; ResizeObserver-driven xterm fits on newly-visible
neighbour tiles then re-blurred it ~10ms after the rAF that #181
used to re-focus.setFocusedTilenow polls across up to 8 frames
and re-establishes focus wheneverdocument.activeElementdrifts
off the target's helper-textarea, idempotently. The gate decision
is extracted into a puredecideFocusActionhelper with unit
tests, and the regression class is now covered by Playwright E2E
via a real xterm + Wails-mock harness. (#186) -
macOS: "Restart Hive" killed hived but the new GUI never appeared.
spawnNewGUIre-execed the inner Mach-O directly, which spawns a
process but doesn't go through LaunchServices, so the relaunched
Wails/WebKit window never gained focus (often never rendered). When
running inside a.appbundle we now relaunch viaopen -n <bundle.app>;-nforces a fresh instance even while the dying
parent is still around. Dev builds (binary outside a bundle) keep
the existing re-exec path. -
GUI: switching from single-focus to grid mode no longer leaves the
previously focused session visually highlighted but unable to receive
keystrokes. Visual focus (.term-focused) and keyboard focus
(xterm helper-textarea) are now reconciled atomically through a
single state-driven writer, so they can no longer drift across view
transitions, modal open/close, or rename input. (#181) -
Windows: starting a session with an agent (Claude, Gemini, Copilot,
…) opened a barecmd.exeprompt instead of running the agent. The
session spawner unconditionally invoked<shell> -l -i -c <line>,
but on Windows the shell falls back tocmd.exe, which treats
-l -i -cas garbage and drops the command. The spawn path now
branches on GOOS: Unix keeps<shell> -l -i -c <line>(load-bearing
for fnm/nvm/asdf PATH setup); Windows uses%ComSpec% /C <line>
with cmd.exe-aware quoting, which also correctly handles.cmd
shims likeclaude.cmd. (#183) -
GUI: terminal text no longer gets stuck displaying garbled glyphs in
long-lived sessions until the user resizes the window. The xterm.js
WebGL renderer can lose its GL context (browsers cap simultaneous
contexts process-wide, so many-tile sessions can trigger this) or
silently invalidate its glyph atlas on device-pixel-ratio changes
and visibility transitions. Each session tile now recovers from
context loss by re-attaching the WebGL addon (or falling back to the
DOM renderer) and forcing a full repaint, and clears the glyph atlas
on DPR changes and on becoming visible again. The GL context is also
disposed explicitly when a tile is destroyed to reduce pressure on
the per-process context cap. (#190)