Commit Graph

3691 Commits

Author SHA1 Message Date
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
Peter Steinberger adf81e14a8 refactor(ui): split notice rendering out of chat-view to restore max-lines headroom 2026-07-21 21:55:43 -07:00
Peter Steinberger e81a2ce657 feat(ui): show chat run startup status (#112339)
* feat(ui): show chat run startup status

* refactor(agents): isolate run status emission

* chore(protocol): refresh startup status models

* refactor(swift): remove unused chat helpers

* test(swift): align retry and i18n fixtures

* fix(swift): restore outbox display helper
2026-07-21 21:25:23 -07:00
Peter Steinberger c780d8b1c0 feat(ui): unify agent pickers with avatars (#112488)
* feat(ui): unify agent pickers with avatars

* fix(ui): close agent picker on draft reset
2026-07-21 21:11:18 -07:00
Peter Steinberger b83af8157b test(ui): reuse shared non-isolated workers (#112493)
* test: isolate OpenClaw home in shared setup

* test(ui): reuse shared workers for pure suites

* test(ui): align scoped runner contract
2026-07-21 21:08:12 -07:00
Peter Steinberger 1a8583ba45 feat(gateway,ui): ask-the-observer questions from the session HUD (#112448)
* feat(gateway,ui): ask-the-observer card input over sessions.observer.ask

* refactor(ui): single home for observer run-identity helper after restack

* test(ui): drop duplicated observer hud test after restack

* test(ui): give the observer ask flow its own colocated suite

* refactor(gateway): leaf observer contract and ask module split for ci gates

* refactor(gateway): drop observer contract re-export shims
2026-07-21 20:59:32 -07:00
Peter Steinberger 153636c702 feat(dashboard): workboard:mini aggregates all boards when boardId is unset (#112484)
* feat(dashboard): workboard:mini aggregates all boards when boardId is unset

* docs: regenerate docs map
2026-07-21 20:32:33 -07:00
Peter Steinberger 3c3a712913 fix(ui): keep chat author identity readable (#112357)
* fix(ui): keep attributed chat identity readable

* test(ui): verify hover-only chat metadata
2026-07-21 19:40:05 -07:00
Peter Steinberger 6c3caa38ab fix(ui): allow direct sessions in non-Git folders (#112433)
* fix(ui): allow direct sessions in non-Git folders

* test: align New Session fixtures with place picker

* fix(ui): preserve worktree intent on Git probe failures

* fix(types): keep worktree status alias internal
2026-07-21 19:36:53 -07:00
Peter Steinberger 0f066eec81 feat(dashboard): plugin widget kinds — native WorkBoard card and mini-board widgets (#112434)
* feat(board): add plugin widget kinds

* feat(ui): render native Workboard widgets

* fix(dashboard): compose plugin widgets with current main

* chore: internalize widget-kind contribution types

* fix(ui): retry plugin widget renderer loads

* fix(ui): harden Workboard widget refresh lifecycle

* fix(ci): clear plugin widget landing gates

* fix(boards): migrate plugin widget storage

* fix(db): migrate unreleased board widget constraint

* fix(ui): retry failed Workboard widget loads

* fix(ui): keep stale widget refresh cleanup inert

* fix(ci): align plugin widget landing guards
2026-07-21 17:59:20 -07:00
Peter Steinberger f0c43dcf72 feat(ui): format international phone numbers for display (#112400)
* feat(ui): format phone numbers for display

* ci: track normalization package exports in Knip
2026-07-21 17:10:25 -07:00
Peter Steinberger 1f0a3ecc68 feat(ui): session observer HUD, sidebar subtitles, and settings (#112260)
* feat(ui): session observer HUD, subtitle integration, and settings

* test(ui): observer demo fixtures for the mock control-ui harness

* fix(ui): satisfy lint and deadcode gates for observer surfaces

* test(ui): adopt renamed pull-request summary api after rebase

* fix(ui): clean rebase artifacts in observer test files
2026-07-21 17:05:14 -07:00
Peter Steinberger 440539b538 feat(workboard): routable boards, sidebar pinning, icon and color (#112302)
* feat(ui): add Workboard board routes and pins

* fix(ui): reject malformed Workboard board catalogs

* perf(ui): lazy-load Workboard sidebar runtime

* test(ui): align sidebar board fixtures with render contract

* fix(ui): clear Workboard landing gates
2026-07-21 15:16:38 -07:00
Peter Steinberger 98742bc2c7 feat(cron): stream schedule sources with durable source identity (#112387)
* feat(cron): stream schedule sources (supervised command stdout)

Add gated argv stream schedules with bounded line batching and trigger.streamBatch composition.

Reuse the gateway ProcessSupervisor for source ownership, deterministic teardown, capped restart backoff, and schedule-key guarded batch execution. Expose additive protocol, CLI, tool, UI, docs, and generated snapshot surfaces without storage DDL.

Contract: stream schedules are event-driven, require cron.triggers.enabled, reject command payloads, and retain at most one bounded pending batch.

* fix(cron): reject retired stream source epochs at run admission

Thread an invalidatable per-owner source-generation token (ownerNonce.generation)
through cron.run admission alongside the schedule key. A batch handed to cron.run
under one source epoch can wait behind another run while its owner is stopped; a
disable→re-enable or A→B→A edit leaves the schedule key unchanged, so the key
check alone would admit the retired epoch's batch. The token is persisted in
job.state on every lifecycle write and compared at every admission site plus the
executeJobCore guard, so a stale epoch's batch is skipped.

Also fix direct stream-job mutations recording the wrong lifecycle status when
global cron is off but triggers are on: extract resolveStreamStopReason so the
direct path reports the remediable cron-disabled state like reconcile does.

* fix(cron): close stream admission windows from round-10 review

- Persist the retired source generation before draining stop teardown, so a
  batch queued behind another cron run cannot gain admission during the up-to-10s
  in-flight-batch wait (server-cron routed stop path).
- Add streamSourceGeneration to the closed gateway response schema (excluded from
  the writable patch schema) so a running stream job passes strict result
  validation without letting callers spoof source identity.
- Close the mutation-epoch ABA: track an eviction epoch so a snapshotted absent-0
  is trusted as unchanged only when no LRU eviction happened during the await.

* refactor(cron): stream sources own a durable logical identity

Split the conflated restart-generation/admission token into two concepts:
a persisted streamSourceIdentity owned by cron store mutations (rotates on
enable/disable, source replacement, once-trigger auto-disable, and explicit
retirement; stable across supervised child restarts) and a watcher-local
process generation used only to fence stale child callbacks. Admission now
requires schedule key + identity together at every window, closing the
A-to-B-to-A and restart-flush races from review rounds 8-11.

Also: match-mode regexes now see raw source text (the [truncated] marker is
applied after matching), stop-timeout failures set the live restartExhausted
mirror so shutdown preserves the terminal diagnostic, and the watcher is
split into owner/output/registry modules under the max-lines budget.

* fix(cron): harden stream teardown and intake from round-4 review

An exit queued ahead of a requested stop no longer counts toward restart
exhaustion (the synchronous stop fence owns it), overlapping cron.stop and
stopAndDrain share one memoized shutdown drain instead of double-stopping
every owner, raw output intake is bounded at 4x the batch cap so normal
64 KiB pipe reads stop losing complete lines to OS chunk boundaries, and
persisted-shape quarantine coverage for unsafe match expressions is pinned.

* fix(cron): keep watcher-internal owner disposal from retiring live identity

Disposing an obsolete owner while a start replaces it is not a durable
removal; a retiring stop there rotated the live job's identity and stranded
the replacement behind the CAS ownership guard. Also align the docs with the
implemented match semantics: complete lines match on full text past the
batch cap, only intake-cut prefixes are unmatchable.

* fix(cron): make oversized-line matching independent of pipe chunking

Partial lines are retained up to the raw-intake bound rather than the
delivery cap, so a complete over-cap line matches identically whether it
arrives in one callback or several; only a line the intake bound itself cut
remains an unprovable prefix. Reconcile also contains schedule-replacement
stop failures per job, matching the other stop branches.

* fix(cron): bound assembled lines, drop stale payload override, barrier stopAll

- enforce the 4x raw-intake per-line cap while assembling split callbacks,
  so an oversized line stays an unprovable prefix regardless of chunking
- stop passing the watcher-cached payload as a cron.run override; the run
  snapshots the persisted payload under its admission lock
- stopAll waits for every owner stop to settle before surfacing failures
- split cron-stream-output interleaving tests into their own file (max-lines)

* fix(cron): address first full-CI round (lint, knip, schema test, unused param)

* chore(cron): refresh codex prompt snapshots for stream schedule schema

* fix(cron): keep the first clean line after an intake drop ending at a newline

* fix(cron): fence stream reconcile list snapshots against direct mutation routes

A cron.list snapshot captured across the reconcile await could be applied
after a direct add/update route already started the owner, stopping it as
removed and retiring its live identity. A mutation revision bumped at every
direct route start invalidates the stale snapshot; reconcile re-lists
(bounded) instead of applying it.

* style(cron): format stream owner imports

* fix(cron): discard severed stream prefixes at EOF

* fix(cron): retry failed stream shutdown drains

* fix(cron): honor stream stop fence after output drain

* chore(cron): refresh landing checks
2026-07-21 15:01:30 -07:00
Jason (Json) c4911a2c77 improve(ui): simplify coding agent session headers (#112354)
* improve: simplify coding session catalog headers

* improve: simplify coding session catalog headers
2026-07-21 15:27:49 -06:00
Peter Steinberger 3a1351a303 fix(cron): show script automations across user clients (#112195)
* fix(cron): preserve script jobs across clients

* chore(i18n): refresh native cron strings

* chore(i18n): align rebased native catalogs

* chore(i18n): defer generated locale refresh
2026-07-21 08:02:59 -07:00
Qiong b192d3dfb0 fix(control-ui): restore native context menu when text is selected (#106765) (#107137)
* fix(control-ui): restore native context menu when text is selected (#106765)

* test(control-ui): prove selected-text context menus

* fix(control-ui): combine selection and message actions

Keep message actions on selected chat text and add an exact-selection Copy entry, resolving #106765 while retaining the contributor context-menu work.

Co-authored-by: Qiong <yang.ji2@xydigit.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-21 08:01:41 -07:00
Peter Steinberger 025e6ceee0 fix(ui): theme board fixture dropdowns (#111998) 2026-07-21 07:22:16 -07:00
Peter Steinberger 8283e976ed fix(ui): close hovercards after route replacement (#112291) 2026-07-21 05:52:33 -07:00
Peter Steinberger 0b045614f5 fix(ui): cancel stale selection popup timer (#112290) 2026-07-21 05:50:28 -07:00
Peter Steinberger b2aa21612d feat(ui): show PR status on Claude threads (#112180)
* feat(ui): show PR status on catalog threads

* fix(ui): complete PR summary protocol artifacts

* perf(anthropic): bound PR metadata deduplication
2026-07-21 05:01:04 -07:00
Peter Steinberger 92bfb7a91e fix(ui): token activity heatmap never fits without horizontal scrolling (#112006) 2026-07-21 03:41:33 -07:00
Peter Steinberger 0f8a87ad6f fix(ui): prevent narrow chat content overlap (#112012)
* fix(ui): keep narrow chat content readable

* fix(ui): preserve chat layout during resize

* fix(ui): align stream layout with footer state
2026-07-21 03:16:26 -07:00
Peter Steinberger cec17abe55 feat(ui): calm the working claw, rare stances, wait phrases, turn recap (#112060)
* feat(ui): calm the working claw and add turn status whimsy

The working indicator claw now claws in place (jaw snips, no lateral
shadowboxing) with rare seeded stances: mirrored southpaw, double-time
flurry, fake-3D turntable spin, the old punch combo as a rare shadowbox,
and a somersault backflip. After 30s of quiet the status line adds
rotating crab-gerund phrases (Clawing…), and a completed run leaves a
sticky 'Done in 51s · 485 tokens' recap row fed by the session row's
per-run runtime and output tokens. Recap attribution is guarded by a
watch/settle state machine (baseline terminal stamps, absorb, expiry);
the residual without gateway run identity is documented in code.

* fix(ui): unexport test-only working-phrase timing constants

knip's production scan forbids exports only consumed by tests; the test
mirrors the two literals with a pointer comment.
2026-07-21 02:55:44 -07:00
Peter Steinberger a43d53e4fa fix(onboarding): label and mask wizard inputs (#112233)
* fix(onboarding): label and mask wizard inputs

* test(matrix): type sensitive prompt fixtures
2026-07-21 02:46:35 -07:00
Peter Steinberger a575b85a9a fix(ui): request media permission from device pickers (#112037) 2026-07-21 02:13:41 -07:00
Peter Steinberger a44efc0348 improve(ui): device-family icons in Places and shared platform labels (#112209)
Places rows now carry destination icons: monitor for the Gateway and
Mac-family nodes, a phone glyph for phone-family devices, and a server
glyph for cloud workers. The platform prettifier moves from the devices
inventory page into ui/src/lib/platform-label.ts so place-picker
tooltips and Settings/Devices render identical platform names (macOS,
not darwin).
2026-07-21 01:46:11 -07:00
Peter Steinberger 3d3fd97c7d fix(ui): tighten Labs settings spacing (#112038) 2026-07-21 01:28:32 -07:00
Vincent Koc c7a97f4337 fix(ui): refresh untranslated settings and logs keys (#112181) 2026-07-21 16:15:06 +08:00
Peter Steinberger c66c55abfd fix(ui): keep sessions hub tabs stationary (#112039) 2026-07-21 00:57:24 -07:00
cyberic68 01a67233d7 fix(ui): honor configured chat width across conversation (#107261)
Apply the existing chat width setting to tool lanes, activity rows, tool shells, the composer, and its pull-request rows while preserving every default cap.

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-21 00:54:27 -07:00
Vincent Koc 69d821569c fix(ui): exit onboarding when setup is skipped (#112165)
* fix(ui): exit onboarding when setup is skipped

* fix(ui): satisfy onboarding validation gates

* fix(ui): keep transcript helpers module-local

* style(ui): format transcript helper
2026-07-21 15:38:52 +08:00
Miorbnli 5b3e01ba3e fix(ui): format cron run token counts and durations consistently (#108014)
* fix(ui): format cron run token counts and durations consistently

The cron run entry rendered raw unformatted token counts ("1234567 tokens")
and raw millisecond durations ("90000ms"), inconsistent with every other usage
and duration surface in the app which uses formatTokens ("1.2M") and
formatDurationCompact ("1m 30s"). An unknown duration showed "0ms" which is
misleading — it implies an instantaneous run rather than missing data.

Use formatTokens for token counts and formatDurationCompact for durations,
showing n/a when durationMs is absent, matching the rest of the UI.

Co-Authored-By: Claude <noreply@anthropic.com>

* test(ui): cover cron run metric rendering

Co-Authored-By: ZCode <noreply@zcode.ai>

* fix(ui): avoid raw duration fallback text

Co-Authored-By: ZCode <noreply@zcode.ai>

* chore(ui): refresh cron raw-copy baseline

Co-Authored-By: ZCode <noreply@zcode.ai>

* test(ui): localize invalid cron durations

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: ZCode <noreply@zcode.ai>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-21 00:30:21 -07:00
Dallin Romney 2fcbc136c4 fix: show accurate quota and rate-limit alerts (#112047)
* fix: distinguish OpenAI quota errors

* fix: preserve structured billing details

* fix(auto-reply): scope generic rate-limit copy

* fix(auto-reply): preserve fallback exhaustion scope
2026-07-21 16:26:20 +09:00
Peter Steinberger ae27ee98f0 feat(ui): expand the lobster pet's random universe (#112073)
* feat(ui): expand lobster pet randomization

Shiny rolls (1/512) with Lobsterdex tracking, cotton candy and lumen
palettes, crusher/pincer claw asymmetry, freckles, seeded eye glints,
elder and old-friend rare loads, balloon/bubble entrances, snail/duck/
jellyfish ledge traffic with per-kind crossing times, passer reactions,
a message-in-a-bottle event, National Lobster Day monocles, and a golden
ledge trim for a completed Lobsterdex.

* style: apply oxfmt formatting to lobster pet files

* refactor(ui): split lobster pet art and ledge traffic into modules

lobster-pet-sprites.ts owns the static SVG art, lobster-pet-traffic.ts
owns passer/bottle scheduling as a ReactiveController, and load identity
(elder, old friend, dex completion) moves into lobster-pet-plans.ts;
keeps lobster-pet.ts and lobster-pet-look.ts under the max-lines cap and
fixes the passerBaseStyle consistent-return lint.

* fix(ui): clear ledge traffic on disconnect, hide bottle from AT

Review findings: a host reconnect no longer shows a frozen passer or an
unebbing bottle, and the bottle joins the rest of the decorative ledge
sprites behind aria-hidden (fortunes stay on the native-tooltip channel
by design - no i18n surface).

* style: oxfmt formatting for lobster plans/sprites/pet

* refactor(ui): narrow lobster plan/traffic exports to production consumers

isLobsterElderLoad and planLobsterOldFriend become module-local (tests
prove them through resolveLobsterLoadIdentity), and the traffic
controller's hook/scene types stay local; fixes the knip production
unused-export gate.

* fix(ui): request host update when disconnect clears ledge traffic

Lit does not re-render on reattach by itself; the queued update makes
sure a detached-then-reattached pet never shows a stale passer/bottle.
2026-07-21 00:18:54 -07:00
Leon-SK668 9ad0a978f7 fix(ui): preserve graphemes in provider icons (#109509)
* fix(ui): preserve graphemes in provider icons

* fix(ui): clamp uppercase provider icon graphemes

* test(ui): cover provider icon graphemes in Chromium

* test(ui): ignore fallback icon template whitespace

* test(ui): capture complete fallback icon proof

* test(ui): align provider probe E2E scope

Co-authored-by: Leon-SK668 <17695126+Leon-SK668@users.noreply.github.com>

---------

Co-authored-by: Leon-SK668 <17695126+Leon-SK668@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-21 00:17:15 -07:00
Vincent Koc cec527a58a fix(ui): align settings search with navigation rows (#112172)
* fix(ui): align settings search with navigation

* fix(ui): separate scrolled settings navigation
2026-07-21 15:16:06 +08:00
Peter Steinberger dd6e366d94 improve(ui): show real machine identity in the place picker (#112162)
* improve(ui): show real machine identity in the place picker

The place picker labeled the gateway destination with a hardcoded
'Gateway · local' and let duplicate device names collide. The gateway
destination now shows the host's machine name via the existing
system.info method (falling back when unavailable), node rows carry
platform/model/IP facts as tooltips, and duplicate labels — same-named
devices and same-basename recent folders — get a deterministic muted
suffix chosen collision-only (model, then IP, then id; parent folder,
then path, then node facts for recents). IP addresses never render
inline by default. Phone-family nodes get a phone chip icon.

* fix(ui): appease prod-type and no-shadow gates in place identity helpers
2026-07-21 00:12:27 -07:00