mara on #5034: "effort shares /models fate". The per-agent web UI no
longer sets effort: the `/effort` slash command, the effort picker,
`POST /api/effort`, `Bus::set_effort`, the `hyperhive-effort` writer,
`EFFORT_LEVELS`/`is_valid_effort` and the ACP effort-list payload are
gone, and `lib/modelEffort.ts` with them. The effort chip is
display-only and shows its source (`effort_source` in `/api/state`);
on ACP it stays hidden while the session offers no effort level.
The read side is unchanged: with no swarm value an agent runs an
existing `hyperhive-effort` file, else its agent.nix effort, else
medium. Existing files are not touched.
Refs #5034
The per-agent web UI no longer sets the model: the `/model` slash
command, the model picker, `POST /api/model`, `Bus::set_model` and the
`hyperhive-model` writer are gone. The model chip is display-only and
shows where the model comes from (`model_source` in `/api/state`). The
model is set on the swarm (swarm UI agents page, `swarmctl agent
inference set`).
The read side is unchanged: with no swarm value an agent runs its
agent.nix model, else an existing `hyperhive-model` file, else haiku.
Existing files are not touched.
With the picker gone, its model list goes too: `available_models` in
`/api/state`, the ACP model-list filter, and the harness's global
`HIVE_AVAILABLE_MODELS`. The subagent daemon keeps its own
`HIVE_AVAILABLE_MODELS` from mcp.nix, and the `availableModels`
assertion stays.
`/effort` (command, picker, route, file) is unchanged.
Refs #5034
Same gap #4611 fixed for logout: the Preact rewrite's StatusChips menu
never picked up new-session as a click path, only /new-session typed
twice into the terminal. postNewSession already existed in
termActions.ts. Wire it into the status menu with the same arm-then-
confirm click pattern logout/cancel-turn already use.
Closes#4612
mara: 'hive ui agent term: logout button gone? must have dropped with
one of the redesigns, pls bring it back or tell me where to find it'
It did drop, silently. The old app.js overflow menu had an
unconditional 🔓 logout item (dashboard-link + rebuild + new-session +
logout); the Preact rewrite's Root.tsx comment explicitly documents
dashboard-link moving to MetaNav and rebuild being removed outright,
but says nothing about logout — it just didn't come along. `/logout`
still works (TermInput's slash-command list, type-twice-to-confirm),
but nothing in the UI points at it or offers a click path anymore.
Fix: add a 'logout' entry to the status badge's dropdown (StatusChips'
StatusMenu) — the same menu that already hosts pause/resume and
cancel-turn, reusing its exact click-then-confirm-click pattern
(danger: true, armed/confirm state reset on close). Unlike cancel-turn
it's not gated on `thinking` — always offered, matching the old
overflow menu's unconditional entry. Wired through onLogout ->
termActions.ts's existing postLogout (already used by the slash
command, so the only new code is the menu entry + prop threading).
Scoped to just what was asked: /new-session has the identical
gone-from-any-menu gap (same old overflow item, no restored click
path), left alone here and flagged separately rather than folded in.
tsc --noEmit clean, nix fmt clean.
Pure `nix fmt` output from the commit before this one — no hand edits.
203 files: 52 md, 42 tsx, 32 js, 32 css, 21 ts, 13 html, 8 json, 3 mjs.
Reproduce with `nix develop -c nix fmt` on the parent commit; the result
should be byte-identical to this tree.
None of the 13 `.prettierignore` entries appears here — verified by
intersecting the changed-file list against the ignore file, with a
control proving the intersection finds a match when one exists.
mara, #3775: clicking a badge with its own dropdown open reopens it
instead of closing it. Root cause: the outside-click listener only
excludes the dropdown's own ref, not the sibling trigger that opened
it — a click on the trigger closes via that listener (pointerdown
fires first), then the trigger's own onClick toggle fires straight
after and reopens it, since its closure reads the pre-close state.
Dropdown now takes an optional anchorRef (the trigger's wrapper,
which callers already have for CSS positioning) and excludes it from
the outside-click check too — the same shape MetaNav's own hand-rolled
popover already uses correctly. Wired into StatusChips's Picker +
StatusMenu and swarm-ui's ComponentsPage demo (the only three Dropdown
consumers).
Verified two ways: reverted the fix, rebuilt, confirmed the bug
reproduces via a raw-CDP interaction test (two real clicks dispatched
through headless chromium, not just a static screenshot); restored
the fix, rebuilt, confirmed it passes.
mara, #3757: fold the separate alive badge into the turn-state badge,
with pause/resume + cancel-turn moved into its dropdown. Cancel-turn is
click-again-to-confirm, not a modal.
model/effort/ctx/cost stay as separate badges — not asked to fold
those in too.
mara: 'i cannot see if sonnet became claude-sonnet-5 or something
else.' /api/state now carries resolved_model (bus.last_resolved_model(),
already used by serve_common.rs's turn-stats rollup for the same
alias-vs-actual reason) and the model badge shows it as a title
tooltip, same pattern as the ctx/cost badges.
argus (PR review): the thinking-flip useEffect left the button stuck
disabled if the /api/cancel POST itself failed while the turn was
still genuinely thinking, since nothing re-fires the effect. Switch
onCancelTurn's signature to () => Promise<void> and reset cancelBusy
in a .finally() on that promise instead — fires on success or
failure alike, matching app.js's original
postCancelTurn().finally(() => { btn.disabled = false; }).
Root-caused mara's 'no interrupt button on agent term anymore' report:
the pre-rewrite app.js had a visible <button id=cancel-btn> (class
btn-cancel-turn, already-styled CSS still in agent.css but orphaned)
shown only while a turn was in flight, wired to /api/cancel. The
Preact rewrite (agent terminal Preact rewrite) ported the /cancel
slash command but never re-added the visible button, so interrupting
a turn now requires typing a command instead of clicking.
Adds thinking/onCancelTurn props to StatusChips, rendering the same
btn-cancel-turn markup only while turn_state === thinking, wired to
the existing postCancelTurn() (termActions.ts) + refresh(). Verified
with real headless-chromium screenshots against a mock /api/state:
button renders while thinking, is absent while idle.
- StatusChips.tsx: drop the stale 'useAgentState lands in a later
commit' comment now that Root.tsx already wires it.
- nix/checks.nix: add agent-typecheck, same shape as swarm-ui-typecheck,
so a real TS error in the agent package fails CI instead of just
esbuild-stripping silently.
Adds a new Preact/TSX build alongside the existing app.js (esbuild
entry `main.tsx` → dist/static/main.{js,css}, same jsx/tsconfig shape
swarm-ui already uses) and the first real page slice: Header +
StatusChips, composing the Badge/Dropdown components from the prior
commit's PR. Not wired into index.html yet — app.js keeps rendering
the live page untouched while this fills in component by component
(state polling, the live SSE stream, login flow, inbox/todos, term
input) in follow-up commits on this branch.
StatusChips folds the model/effort pickers and pause into the badge
row itself (each badge IS its own control), replacing the old
overflow-menu-only pickers — the concrete fix the design guide already
names this page as needing. Presentational only for now (props, not
live data) so it's reviewable against sample data before being wired
to /api/state.
Screenshot-verified against the real agent.css/theme.css/colors.css
(headless chromium, sample data) — renders correctly.
Builds + tsc --noEmit clean.