Commit Graph

3728 Commits

Author SHA1 Message Date
Peter Steinberger
1e5096c519 refactor(ui): one job per sidebar zone — shell chrome controls, header presence, slim footer (#112936)
* refactor(ui): one job per sidebar zone — move search/collapse to shell chrome, presence to chat header, slim footer

* test(ui): point drawer-collapse e2e step at shell chrome nav toggle

* refactor(ui): unexport lobsterLookStyleVars after logo stand-in removal

* docs(web): describe shell chrome controls, slim footer, and header presence facepile

* fix(ui): keep cluster search on native-nav hosts; draft-aware collapsed new-thread
2026-07-23 05:54:39 -04:00
Vincent Koc
e0a692658e test(ui): cover bundled CLI brand icons 2026-07-23 17:43:10 +08:00
Vincent Koc
84d149bf6f fix(ui): use bundled model setup icons 2026-07-23 17:43:10 +08:00
Peter Steinberger
f466c3de32 refactor(ui): collapse sidebar inheritance tower (#112969) 2026-07-23 04:44:25 -04:00
Peter Steinberger
6a90ad0573 refactor(ui): move sidebar menus into a reactive controller (#112940) 2026-07-23 03:15:20 -04:00
Peter Steinberger
07f671724c test(ui): wire catalog project activity case through sessionData catalogs 2026-07-22 23:03:16 -07:00
Peter Steinberger
d9c9dcf71e test(ui): update sidebar-customization e2e to current nav defaults (custodian in settings, advanced-tier search, plugin tabs in sidebar) 2026-07-22 22:56:27 -07:00
Jason (Json)
6504cf85f2 fix(ui): restore project hierarchy and session activity (#112924)
* fix(ui): restore catalog project type hierarchy

* feat(ui): show catalog session activity

* chore(ui): update startup budget baseline

* test(ui): isolate catalog activity coverage
2026-07-22 23:43:46 -06:00
Peter Steinberger
5678c74e4d fix(ui): keep system agents out of page scopes (#112889)
* fix(ui): exclude system agents from page scopes

* perf(ui): keep scope filtering within startup budget
2026-07-23 01:38:11 -04:00
Peter Steinberger
b74f04ada8 refactor(ui): move sidebar mutations and groups into one organizer controller (#112923)
* refactor(ui): move sidebar mutations and groups into controllers

* refactor(ui): lazy-load session organizer operations

* fix(ui): order organizer mutation scope before options
2026-07-23 01:37:18 -04:00
Peter Steinberger
6b470b1fe8 fix(ui): thread-changes button leads to a dead end when the workspace is not a git checkout (#112914)
* fix(ui): disable the thread-changes button when the workspace is not a git checkout

* chore(protocol): regenerate Swift gateway models for sessions.files.list gitCheckout
2026-07-23 01:33:35 -04:00
Peter Steinberger
89cfea034a refactor(ui): consolidate workboard controller tests (#112897)
* test(ui): consolidate workboard fixtures

* test(ui): classify workboard fixtures as test-only
2026-07-23 01:25:18 -04:00
Jason (Json)
c2578bddfd fix: commentary no longer repeats after steering a task (#112859)
* fix(ui): preserve stream boundary across steers

* fix(ui): keep stream boundary current during reconciliation
2026-07-22 22:03:25 -06:00
Jason (Json)
3c25222fb4 fix(ui): pin session observer to pane header (#112866) 2026-07-22 21:55:27 -06:00
Peter Steinberger
efc19faca4 refactor(ui): move sidebar session data into controller (#112853) 2026-07-22 23:45:55 -04:00
Peter Steinberger
099d6351b3 refactor(sessions): canonical lineage model — creation provenance, fork ancestry, generation chain, typed row contract (#111861)
* fix(sessions): preserve spawn/fork lineage across implicit daily/idle rollover

* refactor(sessions): canonical creation model with forkSource ancestry and generation chain

* feat(sessions): stamp creation provenance across all creation paths and emit created events

* refactor(gateway): lock lineage patching, split control from navigation, add typed session-row contract

* docs(gateway): document creation provenance stamping and lineage patch tightening

* fix(sessions): keep provenance proof-only on wire fallbacks and strip node-local lineage from cron continuations

* fix(gateway): never journal a created event for session adoption

* fix(gateway): keep post-create work on adoption while gating the created event

* fix(sessions): restore trusted ensure-main provenance and stamp navigation parent at spawn

* fix(sessions): allow parentSessionKey through the direct child spawn patch

* fix(ci): break type cycles, satisfy export scan, regenerate Swift protocol models

* refactor(sessions): replace createdBy with createdActor

* fix(protocol): export session row type

* fix(sessions): preserve proven creation provenance

* fix(sessions): close lineage creation gaps

* test(sessions): align atomic spawn lineage coverage

* test(sessions): widen transcript search reconcile wait

* fix(sessions): stamp reset-created rows

* test(sessions): keep reset provenance coverage focused

* fix(sessions): journal chat-created rows

* test(ci): anchor release skill reads to repo

* test(ci): avoid cached module paths
2026-07-22 22:54:31 -04:00
Jason (Json)
57473e6f7e fix(ui): keep user footer actions together (#112836) 2026-07-22 20:03:58 -06:00
Peter Steinberger
6c5713b6f1 refactor(ui): move sidebar attention into controller (#112817) 2026-07-22 21:15:44 -04:00
Jason (Json)
7eec1345f9 fix(gateway): preserve Control UI access across device-auth upgrades (#112558)
* fix(gateway): preserve device auth upgrade recovery

* fix(gateway): satisfy device auth upgrade gates

* fix(doctor): clean disabled device auth bypass

* fix(gateway): recheck migration operator boundary

* fix(gateway): keep migration guard internal

* fix(gateway): preserve insecure migration access

* fix(gateway): reject stale migration handshakes

* fix(gateway): revoke legacy migration sessions

* fix(gateway): bound device-less migration authority

* fix(gateway): require explicit migration pairing

* fix(gateway): revoke alternate migration sessions

* fix(gateway): close migration admission races

* style(gateway): format migration pairing import

* fix(security): audit pending device-auth migration

* fix(gateway): reconcile migration on startup

* fix(gateway): cap device auth migration scopes

* fix(gateway): retain migration socket restrictions

* perf(ui): trim migration startup bundle

* perf(ui): lazy-load device auth migration

* fix(gateway): bind migration completion to approved key

* fix(gateway): preserve migration authorization bounds

* fix(gateway): grant migrated device pairing capability

* fix(ui): preserve device migration bundle budget

* fix(ui): stabilize migration startup budget

* chore(ui): retain startup budget headroom

* fix(ui): split migration overlay helpers
2026-07-22 18:44:48 -06:00
Peter Steinberger
1a7a1808f7 refactor(ui): replace sidebar render snapshot with host (#112809) 2026-07-22 20:23:59 -04:00
Peter Steinberger
db5e59d15e refactor(ui): extract sidebar session-list render functions (#112753)
* refactor(ui): extract sidebar session-list render functions

* refactor(ui): trim obsolete sidebar render wrappers

* refactor(ui): compact sidebar render snapshot

* refactor(ui): add sidebar startup margin

* refactor(ui): reduce sidebar render duplication

* refactor(ui): reduce sidebar render overhead
2026-07-22 19:30:39 -04:00
Peter Steinberger
3525e06587 test(ui): collapse chat-send request mock boilerplate (#112783)
* test(ui): collapse chat send request mocks

* test(ui): satisfy chat mock lint
2026-07-22 15:23:28 -07:00
Peter Steinberger
f4e465d295 refactor(ui): sidebar cleanups — shared tooltips, one idle-import helper, cross-tab outbox bridge (#112780)
* refactor(ui): sidebar cleanups — shared tooltips, one idle-import helper, cross-tab outbox bridge

Three bounded cleanups following the offline-state work:

- Tooltip unification: every sidebar-family tooltip (session-row badges,
  offline status, agent card, attention actions, brand icons) now uses
  the shared <openclaw-tooltip> component instead of raw title attrs,
  completing the direction #112639 started. Aria labels unchanged.
- One idle-import helper (ui/src/lib/idle-import.ts): the duplicated
  idle-load/retry logic from app-sidebar chrome and app-host's outbox
  loader collapses into createIdleImport (cached promise clears on
  failure, one idle retry while online, online re-arm, dispose). The
  helper migration is net negative at its call sites.
- Cross-tab outbox bridge: subscribeStoredChatOutboxChanges now also
  notifies on storage events for the composer outbox keys, installed on
  first subscribe and removed with the last subscriber, so a message
  queued in another tab refreshes badges here.

* fix(ui): keep idle-import scheduling statement-form for narrow-safe types and consistent-return

* fix(ui): give idle-import a strictly void schedule and promise-only load
2026-07-22 15:21:33 -07:00
Peter Steinberger
4e9ae9fbff feat(cron): system-owned heartbeat monitor jobs replace the dedicated interval scheduler (#112585)
* feat(cron): system-owned heartbeat monitor jobs replace the interval scheduler

- new internal cron payload kind {kind:"heartbeat"}: execution pokes
  requestHeartbeat({source:"interval"}); reported in the protocol job
  schema, not accepted from client create/patch
- gateway converges one declaration-keyed monitor job per heartbeat-enabled
  agent (schedule every+deterministic phase anchor) at startup and on
  config reload; removes monitors for unconfigured agents
- heartbeat runner loses its interval setTimeout machinery; nextDueMs
  stays as the cooldown gate, event wakes unchanged

* test(cron): heartbeat monitor regressions; docs for cron-owned cadence

- converge/prune/failure-containment tests for heartbeat monitor jobs
- heartbeat payload run fires an interval wake, no system event
- scheduler tests converted from timer self-fire to wake-queue pokes;
  timer-mechanics-only tests deleted with the timer
- persisted-shape accepts the heartbeat payload kind
- docs: heartbeat cadence ownership + system payload kind

* fix(cron): heartbeat monitor review round 1

- targeted cron-monitor interval ticks use the full per-agent path so
  due-commitment sessions still deliver
- cron-disabled gateways keep a local fallback interval timer (shipped
  cron.enabled=false contract; removed when heartbeat config folds into
  cron in #110950)
- heartbeat job reconciliations serialize with latest-wins epochs and a
  bounded 30s retry after a failed convergence pass

* fix(cron): chain clamped fallback heartbeat timers past the setTimeout cap

* fix(cron): heartbeat monitor review round 3

- targeted monitor redirect skips wakes carrying heartbeat overrides and
  surfaces the per-agent terminal skip reason instead of not-due
- cron-disabled fallback timer re-arms with a 1s floor after each firing
  so a dropped wake cannot end the chain
- heartbeat payloads are system-owned at the service boundary: add requires
  the gateway opt-in, patches to the kind are rejected

* fix(cron): heartbeat monitor review round 4 — full ownership enforcement

- prune only jobs proven to be monitors (prefix AND heartbeat payload)
- existing monitors reject every update patch; declarative upserts on the
  monitor key require the gateway opt-in even with a different payload

* fix(cron): complete heartbeat monitor ownership boundary

- converge scopes declarative matching to real monitors so a colliding
  user job with the same key is never adopted or overwritten
- monitor removal requires the gateway systemOwned opt-in; ad-hoc
  API/CLI deletion is rejected, reconciliation cleanup still prunes

* docs(cron): record intentional enrollment-snapshot semantics for monitor ticks

* fix(cron): repair heartbeat monitor CI gates
2026-07-22 14:03:29 -07:00
Peter Steinberger
6bf03cd674 fix(ui): keep composer sends on one stable bubble through the history handoff and add a subtle entry animation (#112567)
* fix(ui): keep composer sends on one stable bubble through the history handoff and add a subtle entry animation

* fix(ui): keep userTurnSendIdentity module-local
2026-07-22 13:02:49 -07:00
openclaw-mantis[bot]
e92e338e9c chore(ui): refresh control ui locales (#112673)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-22 11:03:28 -07:00
Peter Steinberger
85fda04df7 feat(ui): surface queued-outbox counts in composer hint, session rows, and offline footer (#112649)
* feat(ui): surface queued-outbox counts in composer hint, session rows, and offline footer

Follow-up to the offline-state unification: queued sends were mechanically
safe (durable outbox with reconnect replay) but only visible inside the
open session's thread.

- Composer offline hint now includes the visible session's queued count.
- Session rows show a clock badge with the per-scope outbox count,
  independent of connection state (covers waiting-idle and failed too),
  with alias-safe scope resolution so agent-main never double-counts.
- The offline footer button appends the aggregate ("· N queued"); the
  connected state stays completely silent.
- One narrow subscription seam (subscribeStoredChatOutboxChanges) added
  in composer-persistence; no send/drain logic touched.

* perf(ui): keep the startup bundle under budget with a lean outbox read module

The queued-count feature statically imported composer-persistence from
startup modules, hoisting the chat page's persistence machinery into the
startup chunk and breaking the Control UI startup JS gzip budget
(319.6 KiB > 314.0 KiB limit).

Split ownership instead of gaming the budget: a lean read/subscribe
module (ui/src/lib/chat/outbox-store.ts + codec/draft-state) serves
startup consumers (app-host, sidebar), while writes, migrations, and
drain stay in the lazy chat chunk (composer-outbox-store/composer-storage);
composer-persistence keeps its export surface for chat callers. Startup
is back to 313.8 KiB gzip at 12 requests with no chunking-config changes.

Also fixes an autoreview finding in the new summary: legacy bare-main
outbox rows now resolve through session defaults (online) or the
persisted mainAlias (offline reload) instead of trusting the row's stale
embedded agent id, so badge counts key to the same scope the sidebar
resolves. The shared footer status renderer is deduplicated into
session-row-badges.

* fix(ui): correct type-only import and const tuple in outbox split

* perf(ui): idle-load the outbox summary so startup carries no outbox code

The lean outbox read module still cost ~2.8 KiB of startup gzip against
1.5 KiB of budget headroom. Follow the sidebar chrome pattern
(lobster-pet/facepile): app-host idle-loads outbox-store, subscribes on
arrival, and passes the sidebar a resolver callback instead of letting
startup modules import scope resolution. Badges and counts hydrate
moments after load; before that the summary is empty by design.

Failed chunk loads recover on browser online events and, because chunks
are usually served by the gateway itself, on gateway reconnect — the
exact moment the offline badges become relevant again.

Raise the initial-graph packing ceiling 448->512 KiB: the grown core
graph split at the old boundary into an extra chunk, costing ~1.9 KiB of
startup gzip to compression-context resets (same documented tradeoff as
the earlier 400->448 bump). Startup lands at 313.5 KiB gzip / 9 requests,
matching the origin/main baseline, limit 315.0.
2026-07-22 10:53:22 -07:00
Peter Steinberger
96d16c3c46 fix(ui): discussion button stays open on second click (#112671)
* fix(ui): toggle discussion sidebar from header

* test(ui): cover discussion sidebar toggle
2026-07-22 08:38:36 -07:00
Peter Steinberger
b680843eb7 fix(ui): keep Model Providers select chevrons on the right (#112530)
* fix(ui): prevent repeated settings select chevrons

Signed-off-by: sallyom <somalley@redhat.com>

* refactor(ui): fix settings select chevron wipe at the root cause

Replace the restored chevron longhands with background-color in the
select.settings-select rule so the .field select chevron (image, repeat,
position) is never wiped, in dark mode too, and scope the 36px gutter to
.field select.settings-select so native-appearance settings selects keep
their 10px padding.

---------

Signed-off-by: sallyom <somalley@redhat.com>
Co-authored-by: sallyom <somalley@redhat.com>
2026-07-22 08:22:43 -07:00
Peter Steinberger
685fb849bb fix(onboarding): recover expired wizard sessions (#112286)
* fix(onboarding): recover expired wizard sessions

* build(protocol): project expired wizard detail to Swift
2026-07-22 06:42:25 -07:00
Peter Steinberger
df3ff35277 refactor(state): move device auth tokens to SQLite (#112663)
* refactor(state): store device auth tokens in sqlite

* fix(state): keep device auth migration types acyclic

* fix(state): keep migration detection type private
2026-07-22 06:13:03 -07:00
Peter Steinberger
cf2f591161 feat(sessions): permanent creator attribution, owner avatars, person filter, multi-user docs (#112658)
* feat(sessions): persist creator attribution

* feat(ui): add session creator filtering

* chore(sessions): refresh sqlite schema baseline

* docs(security): explain shared-agent trust

* fix(sessions): project catalog creator ownership

* fix(ui): restore startup JS budget headroom for creator attribution
2026-07-22 05:47:21 -07:00
Peter Steinberger
0226ad50fa feat(ui): inspect chat images in an accessible lightbox (#112442)
* feat(ui): add chat image lightbox

* fix(ui): preserve image viewer media lifecycles

* refactor(ui): move chat attachment drop handlers

* fix(ui): scope chat image interactions

* fix(ui): preserve Markdown image spacing

* fix(ui): safely open data image originals

* fix(ui): clear stale image lightboxes

* fix(ui): isolate lightbox interactions

* fix(ui): narrow lightbox focus targets

* perf(ui): track linked images in one pass

* fix(ui): satisfy lightbox CI contracts
2026-07-22 05:37:38 -07:00
Peter Steinberger
0c99a4e362 feat(ui): manage DM pairing requests in Channels (#112401)
* feat(ui): manage DM pairing requests

* fix(ui): clear pairing data across auth changes

* test(ui): tighten pairing page fixture type

* fix(gateway): complete pairing protocol contracts

* fix(ui): guard pairing mutations across epochs

* fix(ui): restore chat teardown gates

* fix(ui): isolate channel auth lifecycles

* fix(ui): remove stale chat view export
2026-07-22 04:54:20 -07:00
Peter Steinberger
0d7e870a2b fix(ui): move footer title tooltips onto the shared tooltip component (#112639) 2026-07-22 04:47:02 -07:00
Peter Steinberger
01da67e3ff feat(ui): unify Control UI offline state into one indicator and a queueing composer hint (#112600)
* feat(ui): unify Control UI offline state into one indicator and a queueing composer hint

The Control UI showed three competing offline surfaces (top connection
banner, agent-card presence dot, sidebar footer label), each deriving its
own view of the same gateway snapshot with inconsistent debounce.

- Centralize the 2s offline debounce as `offlineStable` in the gateway
  store; delete the sidebar-local timer.
- Delete the connection banner and the agent-card presence dot; the
  gateway link is client state, not agent presence.
- The sidebar footer indicator is now canonical: a single offline button
  with reconnect detail, redacted last-error tooltip, and click-to-retry
  (absorbs the banner's "Retry now"). Connected state renders nothing.
- Settings sidebar footer follows the same offline-only rule (no green
  connected dot).
- The composer shows an offline hint strip ("messages will be queued and
  sent when the connection returns") while staying fully usable; the
  existing durable outbox already replays queued sends on reconnect.

* fix(ui): keep offline debounce constant module-local for knip production scan
2026-07-22 03:31:58 -07:00
Peter Steinberger
92540b8735 feat(ui): redesign session observer HUD with labeled status and visibility-gated digests (#112594)
* feat(ui): redesign session observer HUD with labeled status and visibility-gated digests

* chore(protocol): regenerate app protocol bindings for sessions.observer.visibility
2026-07-22 02:56:10 -07:00
Peter Steinberger
a67b937fce fix(ui): unify tooltip arrows and rework sidebar footer hover cards (#112602)
* fix(ui): unify tooltip arrows and rework sidebar footer hover cards

* fix(ui): keep rich tooltips open while trigger or card retains hover or focus

* fix(ui): type trigger slot query and drop unused build-card export

* test(ui): type usage hint button query for test-types lane
2026-07-22 02:17:35 -07:00
Peter Steinberger
aa35dc8c40 feat(ui): builtin observer board card with digest timeline (#112565)
* feat(ui): builtin observer board card with digest timeline

* fix(ui): satisfy type and deadcode gates for observer board card
2026-07-22 01:44:04 -07:00
Peter Steinberger
d4f19bfd79 feat(sessions): first-class archived-session handling (tri-state filter, pruning exemption, inline archived UI) (#112554)
* feat(sessions): first-class archived-session handling

Archived sessions are now exempt from every automatic maintenance path
(age prune, entry cap, model-run prune, disk budget, cleanup repairs);
only explicit sessions.delete removes them. sessions.list gains an
additive tri-state archived filter (true | false | "all"). The sidebar
gets a persisted Active/Archived/All status filter with inline dimmed
archived rows, replacing the nav-away View-archived button; the Sessions
page toggle becomes the same tri-state with dimmed+badged rows in All
mode; the chat composer's archived notice becomes a full-width banner
with an Unarchive action.

* chore(protocol): regenerate Swift gateway models for tri-state archived filter
2026-07-22 01:28:53 -07:00
Peter Steinberger
db2ea84e9a fix(ui): collapse discussion panel chrome to a single header (#112574) 2026-07-22 01:07:16 -07:00
Peter Steinberger
6f7388c9cc feat(ui): teach the working claw three new rare tricks (#112552)
Zen (2%) breathes through a 6s cycle with one deliberate late snip,
drummer (1%) rocks a two-beat rhythm with jaw hits on the tilts, and
peekaboo (1%) ducks down small and pops back wide open. All three stay
in place (scale/rotate/vertical only); weights rebalance from the
default and southpaw stances.
2026-07-22 00:00:25 -07:00
Peter Steinberger
344feae7a1 fix(ui): hide presence avatar initials fallback when the image renders (#112523)
The initials fallback span inside openclaw-viewer-avatar was hidden with a
single-class selector (.viewer-avatar__fallback, 0-1-0) that the later
.viewer-avatar > span display rule (0-1-1) outranks, so image avatars rendered
the photo and the colored initials side by side in the who's-online roster,
footer facepile, and session facepiles. Bump the hiding selector to
.viewer-avatar > .viewer-avatar__fallback so it wins again; the
.is-fallback swap (0-3-0) still shows initials when the image fails to load.

Regressed in #111421.
2026-07-21 23:58:56 -07:00
Peter Steinberger
b8ccb5dfa9 test(ui): isolate chat pane lifecycle state (#112546) 2026-07-21 23:32:53 -07:00
Peter Steinberger
e01f3e18a7 feat(config): tier settings as common and advanced (#112538) 2026-07-21 23:17:47 -07:00
Peter Steinberger
c670fb0e27 feat(ui): show live output tokens while agents run (#112333)
* feat(ui): show live run output tokens

* fix(ui): map live usage to active runs

* test(ui): split live usage coverage

* fix(agents): scope live usage cleanup

* fix(agents): reject stale live usage events

* fix(agents): keep live usage type local

* refactor(ui): keep chat view within line budget

* fix(agents): require lifecycle for live usage

* refactor(ui): dedupe chat reply target type
2026-07-21 23:10:17 -07:00
Peter Steinberger
70fd8d23c8 fix(ui): keep session narration live across chat switches (#112526)
* fix(ui): refcount session message subscriptions

* chore(release): keep changelog generation release-owned
2026-07-21 22:32:06 -07:00
Peter Steinberger
7014d72752 refactor(ui): unify sidebar row visibility (#112511)
* refactor(ui): unify sidebar row visibility

* test(ui): consolidate sidebar visibility coverage

* style(ui): restore chat view line budget

* chore(ui): drop superseded lint workaround
2026-07-21 22:19:28 -07:00
Peter Steinberger
d823cdc794 fix(ui): normalize nullable workspace conflict in chat-view notices 2026-07-21 22:06:08 -07:00
Peter Steinberger
c7dd7b4be2 fix(pr): rebuild stale prep branches after head changes (#112510)
* fix(pr): refresh stale prep branch on head drift

* fix(ci): repair PR landing gate failures
2026-07-21 21:57:56 -07:00