Commit Graph

5650 Commits

Author SHA1 Message Date
Peter Steinberger a6810bb00e fix(ui): align sidebar unread dot with pull-request rows (#129477)
The trailing unread dot sat 3.5px inboard on rows that also show a
pull-request icon, so the dots did not form one column down the sidebar.

`.session-row-state` centred its glyphs as one flex box, which only lands
the glyph on the action-icon axis when the box holds exactly one glyph.
Give each glyph its own fixed 14px grid track instead, so the trailing
glyph keeps that axis regardless of what precedes it.
2026-08-25 10:26:53 -07:00
Shakker ce62d6db74 test: await lazy sidebar load before teardown (#129376)
* fix: drain lazy UI module loads in tests

* test: await lazy sidebar before teardown
2026-08-25 15:47:28 +01:00
Colin Johnson 081ce11324 feat(ui): add collapsible Workboard columns (#128115)
Co-authored-by: Solver <solver@localhost>
Co-authored-by: Solvely-Colin <211764741+Solvely-Colin@users.noreply.github.com>
2026-08-25 08:22:03 -04:00
Peter Steinberger d94dd51276 refactor(ui): deduplicate workboard metadata normalization (#129280) 2026-08-25 05:03:28 -07:00
Peter Steinberger 4dc7bb7411 chore(deps): refresh dependencies after seven-day cooldown (#129187)
* chore(deps): refresh dependencies after cooldown

* fix(gateway): emit append-only Responses content events

* chore(deps): retain unverified Sherpa runtime
2026-08-25 05:00:46 -07:00
Peter Steinberger 22fa9f5786 fix(linux): first-run desktop onboarding automatically connects working AI (#129211)
* fix(linux): make desktop AI onboarding work automatically

* fix(linux): harden provider ownership and onboarding lifecycle

* test(ui): document partial onboarding context fixture

* fix(linux): preserve operator-owned onboarding API keys

* fix(linux): retire previously managed provider credentials

* fix(linux): retain rotated onboarding provider credentials
2026-08-25 04:47:35 -07:00
Peter Steinberger 1fdd10bf6a fix(gateway): prevent live profile retries from replacing runtimes (#129239)
* fix(gateway): isolate live model session scopes

* test(ui): bound streaming markdown benchmark

* test(gateway): carry prepared live model auth into isolated profiles

* test(gateway): keep fallback sessions write-scoped
2026-08-25 04:44:55 -07:00
Peter Steinberger b579f3ee3f fix(ui): preserve confirmed cloud profile deletion across reconnects (#129245)
* fix(ui): preserve confirmed cloud profile deletion across reconnects

* fix(ui): bind cloud profile deletion to gateway client identity
2026-08-25 04:25:56 -07:00
Peter Steinberger 6fb3303492 perf(ui): parallelize session roster loads (#129175)
Amp-Thread-ID: https://ampcode.com/threads/T-01a037b3-be95-76ea-8fb3-75979929acf1

Co-authored-by: Amp <amp@ampcode.com>
2026-08-25 02:17:18 -07:00
Peter Steinberger 7e8412e080 fix(ui): stabilize the sidebar session list with a single projection owner (#129150)
* fix(ui): stabilize sidebar session list with a single projection owner

The sidebar flickered as gateway events arrived: rows popped out when runs
ended (active/pinned page bypass), rows jumped within createdAt ties after
paging (per-publish created-order pruning), child trees auto-collapsed when
a descendant went idle (per-render derivation), and running-row subtitles
blank-flashed between observer/narration updates.

SidebarSessionProjection now owns all presentation stability for the
sidebar lifetime: sticky page membership with user-action reset boundaries,
a monotonic bounded created-order registry, latched child expansion with an
explicit collapsed-by-user mode, and a last-subtitle hold per active run.
The scattered mechanisms it replaces are deleted (limitSidebarSessionRows,
partitionSidebarVisibleSections, per-publish order pruning, three expansion
key sets).

* fix(ui): hold running-row subtitles across run rotation with a display floor

Live A/B on a dev gateway showed two residual subtitle defects: the hold
was keyed to the exact active-run-id set, so the queued->running rotation
still blanked the row, and racing ambient sources (observer digest,
narration, work path) swapped the line A->B->A within a second.

The hold now lives for the session's running lifetime and ambient
replacements respect a 2s minimum display floor (matching the narration
throttle); attention, agent status, and the queued explanation bypass the
floor because the operator must act on them.

* test(ui): assert subtitle holds on non-localized sources

The run-rotation and critical-replacement tests asserted the localized
queued string through the shared i18n singleton; in the striped ui CI lane
(shared module graph, isolate=false) that resolution is environment-
sensitive and failed in checks-node-compact-large-11. Narration and
agentStatusNote exercise the same hold invariants with raw strings.

* fix(ui): reset sticky sidebar membership when grouping changes

ClawSweeper finding: grouping switches can re-emit the same section id
(e.g. ungrouped) with a different row population, so sticky keys must not
carry across; grouping now joins the membership reset boundary with a
regression row in the boundary table. The created-sort e2e migrates to the
sticky contract: an externally discovered newest session still lands on
top, and the previously visible page is retained instead of evicted.
2026-08-25 02:12:42 -07:00
Peter Steinberger 24898ba894 fix(workers): repair cloud session lifecycle and recovery (#121564)
* fix(workers): repair cloud session lifecycle and recovery

* test(workers): preserve dual-mode provider dispatch coverage

* refactor(workers): centralize inherited profile authorization
2026-08-25 01:48:57 -07:00
Peter Steinberger 5b5fdacfda feat(ui): dock the session progress card beside a wide composer (#129141)
* feat(ui): dock the session progress card beside a wide composer

The progress card had two placements: the companion rail when that side
panel is open, otherwise a collapsed one-line bar stacked inside the
composer box. On a wide chat the composer stays centered at the
transcript width, so the space either side of it sits empty while the
card is squeezed into the composer.

Add a third placement. When the measured free gutter beside the composer
is at least 280px, the card docks into it with its full checklist
expanded; below that it falls back to the existing composer bar, and an
open companion rail still wins. Exactly one placement renders at a time,
now expressed as a closed {card, placement} prop so the composer bar and
the dock cannot both draw the same card.

The gutter is measured from the DOM by a small ResizeObserver controller
rather than derived from the pane width: the transcript width is a
browser-local setting in arbitrary CSS units, and an open side panel
shrinks the conversation column without changing the pane. The dock is
positioned absolutely in that gutter, so the transcript and composer
never shift when a card appears or is dismissed, and its inline-start
edge repeats the composer's own half-width formula through a shared
--chat-composer-side-inset token so the two stay in agreement.

* fix(ui): keep the new-session composer sized outside the chat surface

The composer shell tokens are declared on .chat, but the new-session page
reuses .agent-chat__composer-shell outside it. There the var() had no
value, so the whole width declaration was invalid and dropped, and the
composer stretched full-width instead of holding its 48rem centered box.

Give both tokens their literal fallback at the use site, matching the
neighbouring --chat-thread-max-width. The custodian surface was already
immune because it overrides width outright.

Caught by ui/src/e2e/new-session-page.places.e2e.test.ts, which is the
regression test for this: it failed on the previous head and passes now.
2026-08-25 01:34:09 -07:00
RoboClaw 51825130d8 fix(ui): hide archived threads from sidebar immediately (#129153)
Co-authored-by: roboclaw-bot <309084314+roboclaw-bot@users.noreply.github.com>
2026-08-25 01:32:30 -07:00
RoboClaw e485212348 fix: keep message identity stable through send failures (#129127)
* fix(ui): keep failed sends inline

* fix(ui): preserve editable send failures

* test(ui): assert inline initial-send failures

---------

Co-authored-by: roboclaw-bot <309084314+roboclaw-bot@users.noreply.github.com>
2026-08-25 01:29:02 -07:00
RoboClaw 991a3203d3 fix(ui): align owner avatars with labels (#129133)
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-08-25 01:28:03 -07:00
Peter Steinberger 27e3eac75d fix(ui): preserve loaded history across pane eviction (#126979)
Loaded older Control UI history now remains available after retained-pane eviction and remount, preserving pagination state and the user's visible transcript.

Refs #126978.
Reviewed-by: @shakkernerd
2026-08-25 09:22:44 +01:00
Peter Steinberger 6eaf1b8cb6 refactor(ui): use canonical sessions usage request (#129137)
Amp-Thread-ID: https://ampcode.com/threads/T-01a037b7-8aa3-72eb-95f7-517a508319f6

Co-authored-by: Amp <amp@ampcode.com>
2026-08-25 01:18:30 -07:00
Peter Steinberger 1010a537a3 fix(ui): make session switching and history loading faster (#129111)
* fix(ui): speed up retained chat session switching

* test(ui): keep retained-pane coverage below file size limits

* chore(ui): leave release changelog to generated notes
2026-08-25 01:14:27 -07:00
RoboClaw 49c7fc5bae fix(ui): stop claiming queued sessions need a slot (#129081)
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-08-25 00:19:58 -07:00
Peter Steinberger 8a1ff3966b feat(workers): run OpenClaw and Codex on the same cloud profile (#127752)
* feat(workers): run both harnesses on one cloud node profile

* docs(workers): explain shared OpenClaw and Codex cloud profiles

* fix(workers): preserve trusted Codex cloud enrollment

* docs(codex): clarify bundled cloud plugin eligibility

* fix(workers): honor Crabbox bootstrap retries

* fix(workers): allow cloud profile setup to finish

* fix(workers): reject unsupported cloud execution modes

* refactor(workers): split cloud placement modules

* fix(workers): preserve completed container results
2026-08-25 00:13:29 -07:00
Peter Steinberger bbae605946 perf(test): make update UI proof capture opt-in (#129057) 2026-08-24 23:53:55 -07:00
Peter Steinberger fbf8460da3 refactor(ui): consolidate presence payload parsing (#129029)
* refactor(ui): consolidate presence payload parsing

* chore(ui): tighten presence assertion safety baselines
2026-08-24 23:51:27 -07:00
Vyctor H. Brzezowski 2d0ac795b6 fix(ui): update the new-session model picker when catalogs load (#129019)
* fix(ui): react to model catalog updates

* fix(ui): preserve ready model metadata

* test(ui): isolate model metadata lifecycle coverage

* test(ui): align model metadata lifecycle e2e
2026-08-25 03:50:16 -03:00
Peter Steinberger 1e22f7b85b fix(ui): retain cloud profiles after refresh failure (#128996) 2026-08-24 21:36:19 -07:00
RoboClaw 935c555c98 fix(ui): restore selected dashboard side tab (#128867)
* fix(ui): restore selected dashboard side tab

* test(ui): avoid iframe in side-tab persistence fixture

---------

Co-authored-by: roboclaw-bot <309084314+roboclaw-bot@users.noreply.github.com>
Co-authored-by: Jason (Json) <263060202+fuller-stack-dev@users.noreply.github.com>
2026-08-24 21:58:08 -06:00
RoboClaw fd6576afcf fix(ui): move limited access into Inbox (#128941)
Make the existing Inbox the canonical limited-access surface across desktop, mobile, and onboarding while preserving the scope-upgrade request lifecycle.

Co-authored-by: roboclaw-bot <309084314+roboclaw-bot@users.noreply.github.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-08-24 19:58:34 -07:00
RoboClaw 01311098bc fix(ui): enable slash commands in new-session composer (#128969)
Co-authored-by: roboclaw-bot <309084314+roboclaw-bot@users.noreply.github.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-08-24 19:54:21 -07:00
ClawSweeper b68c136609 feat(codex): upgrade main to app-server 0.149.1 (#128370)
* feat(codex): upgrade app-server integration to 0.149.0

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>

* fix(codex): harden full app-server integration and lifecycle

* fix(codex): scope guardian trust and satisfy integration gates

* fix(codex): keep guardian startup and router tests within gates

* chore(codex): tighten guardian assertion safety baseline

* fix(ui): preserve sidebar icon path contracts

* test(codex): align side-question auth fixture

Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>

* style(codex): format transcript mirror imports

Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>

* test(codex): preserve native approval decisions

Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>

* test(codex): isolate app cache and catalog fixtures

Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>

* fix(ui): render guardian review and system notices

Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>

* test(codex): isolate native approval decisions

Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>

* fix(codex): revalidate reviewer config trust

Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>

* chore(codex): update app-server to 0.149.1

Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>

* test(codex): align desktop version warning

Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>

* fix(ui): scope notices to the active run

Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>

* fix(codex): isolate review, hosted app, and auth ownership

Co-authored-by: Vito Cappello <hixvac@gmail.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>

* chore(codex): keep release notes out of the release-owned changelog

* test(codex): reject reviewer cancellation with its explicit error

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>
Co-authored-by: roboclaw-bot <309084314+roboclaw-bot@users.noreply.github.com>
Co-authored-by: Vito Cappello <hixvac@gmail.com>
2026-08-24 19:50:22 -07:00
RoboClaw c2602ded7c refactor(ui): compact live activity filters (#128972)
Co-authored-by: roboclaw-bot <309084314+roboclaw-bot@users.noreply.github.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-08-24 19:47:55 -07:00
RoboClaw dca05ea39a fix: automation runs appear in creator activity (#128951)
* fix: attribute automation sessions to creators

* test: prove cron session creator isolation

Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>

---------

Co-authored-by: roboclaw-bot <309084314+roboclaw-bot@users.noreply.github.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-08-24 19:37:12 -07:00
RoboClaw 4ded341a28 fix(ui): explain unavailable updates (#128958)
Co-authored-by: roboclaw-bot <309084314+roboclaw-bot@users.noreply.github.com>
2026-08-24 18:57:24 -07:00
RoboClaw b840a3c84e fix(ui): widen mobile chat transcript (#128944)
Co-authored-by: roboclaw-bot <309084314+roboclaw-bot@users.noreply.github.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-08-24 18:27:32 -07:00
RoboClaw ae3d679b12 fix(ui): center completed progress marker (#128911)
Co-authored-by: roboclaw-bot <309084314+roboclaw-bot@users.noreply.github.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-08-24 17:22:31 -07:00
xingzhou 1edbbc9dd7 fix(ui): prevent oversized WebRTC SDP answers from hanging Talk setup (#119295)
* fix(ui): bound WebRTC SDP answer reads and release failed bodies

* fix(ui): scope WebRTC SDP limits to OpenAI

* fix(ui): release bounded response readers

* test(ui): split WebRTC SDP browser coverage

* fix(ui): reject unsafe declared response lengths

* test(ui): reuse pending WebRTC SDP response fixture

* test(ui): use native response for pending SDP body

* style(ui): align pending SDP fixture formatting

* test(ui): capture WebRTC SDP alert proof

---------

Co-authored-by: Patrick Erichsen <patrick.a.erichsen@gmail.com>
2026-08-24 16:41:36 -07:00
Peter Steinberger b1b26be853 fix(ui): show when connected chats cannot receive live messages (#128865)
* fix(ui): surface failed live chat subscriptions

* test(ui): type live message subscription fixtures
2026-08-24 15:42:52 -07:00
Peter Steinberger c50f90251e fix(gateway): surface cloud workspace recovery failures (#128864)
* fix(gateway): record workspace recovery failures

Persist bounded, deduplicated recovery-attempt failures through the session transcript while preserving pending workspace result fences, and prefer current recovery errors over stale terminal reasons.\n\nRefs #128850

* fix(gateway): revalidate recovery transcript ownership

Recheck the canonical session mapping inside the queued transcript transaction so a rebound session cannot receive a stale workspace recovery diagnostic.\n\nRefs #128850
2026-08-24 15:38:25 -07:00
Vincent Koc 0d4e369b1c test(ui): scope Claude session selection to sidebar links (#128874)
* test(ui): scope Claude session link locators

* test(ui): keep Claude locator fix under lint cap
2026-08-24 15:24:18 -07:00
RoboClaw 94bd567674 refactor(ui): flatten tasks page layout (#128853)
Co-authored-by: roboclaw-bot <309084314+roboclaw-bot@users.noreply.github.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-08-24 14:45:48 -07:00
Peter Steinberger a99317ef97 refactor(gateway): unify bounded chat history across transports (#128844) 2026-08-24 13:06:06 -07:00
RoboClaw b4c620b157 fix(ui): compact touch tool rows (#128839)
Co-authored-by: roboclaw-bot <309084314+roboclaw-bot@users.noreply.github.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-08-24 12:43:53 -07:00
ClawSweeper 798c21af7b feat(ui): search sessions and catalogs from command palette (#128356)
* feat(ui): search session context from command palette

Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>

* fix(ui): harden unified session search

Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>

* fix(ui): preserve control UI style budget

Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>

* feat(ui): search command palette catalogs

Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>

* fix(ui): surface incomplete palette searches

Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>

* fix(ui): distinguish incomplete transcript results

Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>

---------

Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>
Co-authored-by: roboclaw-bot <309084314+roboclaw-bot@users.noreply.github.com>
2026-08-24 15:27:12 -04:00
RoboClaw b0e8a985ee feat(ui): load owner sessions before shared roster (#128767)
* feat(ui): load owner sessions before shared roster

Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>

* fix(ui): preserve owner roster across refreshes

Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>

---------

Co-authored-by: roboclaw-bot <309084314+roboclaw-bot@users.noreply.github.com>
Co-authored-by: VACInc <3279061+VACInc@users.noreply.github.com>
2026-08-24 11:50:36 -07:00
ClawSweeper a5b5920444 feat(ui): configure capabilities before session start [AI-assisted] (#128081)
* feat(ui): configure capabilities before session start

Reuse the active-chat Plus menu on new sessions, move Draft into it, and persist admin-scoped tool overrides before the initial turn. Closes #128079.

* test(ui): follow new-session Draft menu

* refactor(ui): reconcile new-session capability ownership

* fix(ui): gate terminal launch on capability overrides

Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>

---------

Co-authored-by: RoboClaw <309084314+roboclaw-bot@users.noreply.github.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-08-24 11:47:12 -07:00
Peter Steinberger d2d58a58c6 test(ui): split settings node suite by concern (#128788)
* test(ui): split settings node suite by concern

ui/src/app/settings.node.test.ts sat at 999 oxlint-counted lines against
the 1000-line max-lines cap, so any added assertion failed the core lint
shard — and, as in #128474, could pass locally while only the merge ref
tripped the cap.

Split the 42-test monolith along the surfaces it actually covers: the
base file keeps gateway URL derivation, tab-local token handling, and
per-gateway session scoping; preference persistence and layout
persistence move to dotted siblings, matching the existing
settings.sidebar-prefs.node.test.ts precedent. Test names and count are
unchanged (47 across the settings node suites, before and after).

The location/base-path/settings-fixture helpers and the storage
lifecycle hooks are now shared from ui/src/test-helpers/settings-node.ts
instead of being copy-pasted per file; sidebar-prefs drops its duplicate
copies too.

* test(node-host): write fake container-engine state atomically

checks-node-compact-large-3 failed twice on this branch in different
tests of node-worker-supervisor.container.test.ts, most recently with
"SyntaxError: Unexpected end of JSON input" raised from the fake engine's
load() while the supervisor ran `docker rm --force`.

The shim saved container state with a truncating fs.writeFileSync while
sibling shim invocations (rm, inspect, wait, ps) read the same path, so a
reader could observe the zero-length window and exit 1. Write to a
".pending" sibling and rename over the target instead; rename is atomic,
so readers always see a complete previous or next state. The ps handler
filters on the ".container.json" suffix, so pending files are ignored.

A concurrent write/read probe over the old pattern produced 2014 partial
reads in 212900; the same probe over write-then-rename produced 0 in
203468. Not reproducible end-to-end on macOS, where the truncation
window is far narrower than on the loaded Linux shard.
2026-08-24 10:10:19 -07:00
Peter Steinberger 053b89d80f improve(ui): open short session links without extra lookup (#128778)
* perf(ui): remove short session route waterfall

* docs: clarify short link gateway requirement
2026-08-24 09:33:20 -07:00
ClawSweeper a6a9f553d0 fix(ui): keep expanded panel controls clear (#128262)
Co-authored-by: RoboClaw <309084314+roboclaw-bot@users.noreply.github.com>
2026-08-24 08:08:01 -07:00
Peter Steinberger 3cf23294a5 refactor(ui): reuse canonical UUID generation (#128753) 2026-08-24 07:39:04 -07:00
Jesse Merhi dea053e32f improve(ui): stop sidebar rows rearranging themselves on hover (#125820)
* improve(ui): put session row actions on the title line

Two-line sidebar rows centred the pin and menu buttons across the whole row, so
they floated between the title and the line below, and hover reserved their
width from the entire text column while fading the status endcap out. Hovering a
row therefore truncated the subtitle and hid its badges, spinner, unread dot and
relative time — the row rearranged itself under the pointer just to show two
controls.

The buttons now anchor to the title line, derived from the link's top padding
plus half the title's line box, and only the title yields their width. The
second line keeps its content and its icons. Single-line rows are untouched:
their one line already is the title line, so #126455's centring and the endcap
beside the title stay exactly as they are.

The reservation is deliberately not transitioned: startHoverMarquee measures
clientWidth synchronously on mouseenter, so an animated width would make long
titles scroll short and would silence titles that only overflow once the buttons
are up.

* fix(ui): keep second-line state lit while the actions are up

Hovering a two-line row to reach the pin or menu also faded its trailing state
out, so the run spinner disappeared under the pointer — the row stopped telling
you it was still working at the moment you reached for its controls.

That trade existed because the actions used to cover the endcap. On a two-line
row they now sit on the title line and cover nothing, so the second line keeps
its spinner, unread dot, badges and time. Single-line rows still trade: there
the endcap genuinely shares the actions' line.

* fix(ui): stop hiding row state and clipping it with the actions

Two problems the first pass left behind, both visible on hover:

The unread dot vanished the moment the pointer arrived on a single-line row.
That row reserves the action width in its text column, which already slides the
endcap clear, but the old fade still ran — so the dot disappeared while the
badges beside it stayed, reading as a glitch rather than a swap. Nothing trades
places with the actions now, on either row shape.

A 24px control centred on the 18px title line also hung 3px into the row below,
so a hovered button's fill would clip the top of the badges that now stay lit
there. Two-line rows shrink the control to the line it sits on; the 14px glyph
is unchanged and coarse pointers keep the full 24px target.

Measured on the preview: single-line endcap ends at 183 with the first action at
186, and the action box now ends exactly where the second line begins.

* fix(ui): even out endcap spacing and drop the touch swap leftovers

The unread dot sat further from the badges than they sat from each other: 6px
between the badges, 14.5px before the dot. The state box carried min-width and
min-height of 24px, sized to match the action button it used to trade places
with, so a 7px dot got 8.5px of padding a side. Nothing trades now, so the box
sizes to its glyphs and the endcap keeps one 6px rhythm.

The touch block kept the other half of that arrangement: state and actions
sharing a grid cell, and the relative-time trail permanently hidden. Both go the
same way — on touch the second line now keeps its content like everywhere else.

Covered by a case whose state holds a single dot, which is the only shape where
the padded box was visible; it reports [6,14.5] against the old CSS.

* fix(ui): draw every session row glyph at one size

The row drew seven different glyph sizes on the same two lines: archive 11px,
badges and spinner 12px, board 13px, fork and the action icons 14px, attention
15px, with stroke widths of 1.6, 1.7 and 1.8 mixed among them. Side by side on
one line that reads as broken alignment rather than a hierarchy.

They now resolve one --session-row-glyph-size and one --session-row-glyph-stroke
declared on .session-row-host, so the whole row moves together and a new glyph
inherits the rhythm instead of picking its own. Every rule keeps its previous
value as the var fallback, so the same components rendered outside a session row
are untouched.

The unread dot stays 7px: it is a dot rather than a glyph, and matching it to a
14px line icon would turn it into a blob.

A test walks a row carrying badges, fork provenance, a spinner and the action
icons and asserts one distinct size across them; against the old CSS it reports
["14x14","12x12"].

* fix(ui): size the session row run ring optically

The ring inks its whole box while the line icons beside it only ink 9-10px
of their 14px box, so unifying it to the glyph token made it read a size
larger than the pin and menu glyphs on the same line. Give the row host its
own ring token three px down from the glyph size; surfaces outside a row
keep the ring's previous 12px.

* fix(ui): put the whole session row trailing column on one grid

The action buttons stepped 25px inside 24px hover targets while the endcap's
badges stepped 20px and ran flush to the row edge, so a badge, dot or ring
never landed under the icon above it. Derive both gaps and the endcap's inset
from the action box, and give the state group a glyph-wide floor so bare
shapes centre on the same axis as icons drawn in a box.

* fix(ui): tighten the session row trailing column

Matching the endcap to a 24px action box spaced the badges 11px apart, which
read airier than before the grid landed. Take the action box to 20px so the
pitch drops to 21 and the badges return to a 6px-ish gap, derive the title's
hover reservation from that box instead of a fixed 52px, and let touch keep
the square button on two-line rows now that no hover fill can clip the badges.

* fix(ui): type the session row test fixtures and endcap lookups

check:test-types caught three errors the ui lane does not cover: the badge
fixtures pass hasAutomation and incognito, which the sessionRow helper never
declared, and the endcap gap probe indexed a possibly-empty NodeList.

* fix(ui): repair session row hover review findings

* fix(ui): preserve catalog sidebar interaction state

* fix(ui): preserve catalog interaction state during rerenders

* perf(ui): keep session rows within CSS budget

* test(ui): satisfy immutable array lint

* fix(ui): preserve catalog identity across session release

* fix(ui): remeasure adopted row live state
2026-08-24 23:40:26 +10:00
RoboClaw b751401560 fix(ui): keep message context hover above transcript rows (#128739)
Release note: message context details now remain fully visible when opened above a virtualized transcript row.

Co-authored-by: roboclaw-bot <309084314+roboclaw-bot@users.noreply.github.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
2026-08-24 06:39:37 -07:00
Peter Steinberger b145e25fea fix(ui): resume session starts after Gateway reconnects (#128661)
* fix(ui): resume session creation after reconnects

* improve(ui): remove redundant appearance reset buttons

* fix(ui): align session protocol and appearance validation

* fix(ui): retain promoted placement session ownership

* fix(gateway): isolate session creation capacity by owner

* test(ui): stabilize hovercard bridge pointer movement
2026-08-24 06:36:51 -07:00