Commit Graph

87 Commits

Author SHA1 Message Date
Vyctor H. Brzezowski e741649856 fix(ui): keep prose fences fully visible (#126346) 2026-08-19 21:05:51 -03:00
Peter Steinberger 347a0eaf8c feat(ui): activity feed automation grouping, live status, deep-link inspector (#125981)
* feat(ui): collapse automation sessions in activity feed

* feat(ui): show live run status on activity feed rows

* feat(ui): make run inspector deep-link only

* fix(ui): only link inspect run to a current active run

Addresses ClawSweeper P1: a stale observer digest could deep-link a live
row to an ended run's audit record; trust digest runId only when it is
still in activeRunIds.
2026-08-18 13:49:25 -07:00
Peter Steinberger ab2bd4faa8 feat(ui): consolidate activity filters into toolbar with people popover (#125917)
* test(ui): seed mock activity sessions across owners

* feat(ui): consolidate activity filters into toolbar

Also restores the shared .input styling contract for standalone form controls.

* test(ui): update activity feed e2e for toolbar people popover
2026-08-18 11:41:06 -07:00
Peter Steinberger f8ba65636c feat(control-ui): simplified settings experience for non-admin operators (#125492)
* test(control-ui): add --operator-scopes flag to the mock dev server

* feat(control-ui): simplified settings experience for non-admin operators

Non-admin browsers previously saw every settings page, many of which
dead-ended or rendered enabled controls whose RPCs fail with
'missing scope: operator.admin'.

- config.schema drops from operator.admin to operator.read: the schema is a
  static document describing options whose values are already readable via
  read-scoped config.get; admin-only schema only broke read-only settings
  rendering (Automation/Infrastructure/AI Agents/Communications showed
  'Schema unavailable. Use Raw.').
- Settings sidebar and settings search hide admin-only routes (custodian,
  labs, updates, automation, infrastructure, mcp, security, secrets,
  cloud-workers, communications, ai-agents, model-setup) for non-admin
  viewers; legacy gateways without advertised scopes keep the full UI.
- Channels, Devices, Worktrees, Memory Import, Profile gate their mutation
  controls on actual scopes with 'Browsing only…' notices instead of
  enabled-but-failing buttons; Devices no longer fires device.pair.list /
  exec.approvals.get without the scopes to call them (kills the two red
  error callouts on page load).
- Scope-upgrade banner: dismissing it in the guidance phase (no in-app
  upgrade path) now hides it fully instead of leaving a permanent chip.
- Config write coordinator surfaces scope refusals as a visible
  admin-required error instead of silently resolving false.

* test(control-ui): advertise config.schema in the mock dev gateway

ensureSchemaLoaded now checks method advertisement + scope before loading
the schema; the mock harness must advertise config.schema like a real
gateway does or schema-driven settings pages render empty in the mock.

* fix(control-ui): close the worktree create draft on scope downgrade

* perf(doctor): isolate memory health artifact

Doctor lint loaded the broad Memory Core API barrel only to register health checks and read isolated check IDs. That synchronously pulled the full memory public graph into the first lint run, consuming most of the 120-second test budget.

Load a dedicated doctor-health public artifact instead and verify it is packaged. The bisect boundary was 9de3ca5fc9 (#125571); because that commit only adds upgrade-test assets, it exposed a pre-existing runner-sensitive cost rather than introducing the expensive import path.

* test(control-ui): restore device lifecycle test boundary

* perf(control-ui): lazy-load settings sidebar

* fix(ui): recheck access after confirmations

* fix(control-ui): gate presence-driven device reloads on pairing access

The presence connectivity-change path still called device.pair.list without
operator.pairing, the same invariant the pair-event and poller paths already
guard; a limited browser got a doomed RPC on every connectivity change.

* fix(control-ui): fail open on schema loads for legacy scope-less gateways

canCallGatewayMethod hardened to strict advertisement+scope checks (#125478),
which made the new ensureSchemaLoaded gate silently skip config.schema for
legacy hellos without advertised scopes or a method list. Schema loads now
skip only on a definitive denial (method advertised absent, or advertised
scopes without operator.read), reusing the fail-open hasOperatorReadAccess
semantics the rest of the non-admin UI uses; regression test pins the
legacy snapshot path.

* test(control-ui): split schema-access coverage into its own file

runtime-config-capability.test.ts crossed the max-lines cap; the legacy
fail-open regression and its denial counterpart move to a colocated
schema-access test file.

* fix(scripts): keep mapped Vitest lanes at their measured no-output floor

The codex extension shard legitimately works in silence beyond 300s under
the default reporter (measured 61s import + 293s testing at ~95% CPU); the
CI-wide OPENCLAW_VITEST_NO_OUTPUT_TIMEOUT_MS=300000 env override shrank the
lane below that and the watchdog killed healthy runs, flipping with
incidental flake output (#125825). Per-config entries in
VITEST_CONFIG_NO_OUTPUT_TIMEOUT_MS now act as measured silence floors: a
global env value may widen a mapped lane's window but no longer shrinks it;
unmapped configs and the explicit '0' disable keep env verbatim. Adds the
codex extension lane to the map at the extra-long tier (same class as the
discord entry from #123025).
2026-08-18 10:15:10 -07:00
Peter Steinberger 4048ae26e0 feat: credit linked session participants as Git co-authors (#125827)
* feat: credit linked session participants as co-authors

Authenticated profiles can link GitHub and receive automatic co-author credit in shared coding sessions.

* style: format rebased co-author registries

* fix: mark profile schema DDL boundary
2026-08-18 07:15:01 -07:00
Peter Steinberger f886ab181e fix(ui): align session owner filtering terminology (#125645)
* fix(ui): align session owner filtering terminology

Owner filters now use owner terminology consistently across the Gateway, Control UI, and generated native protocol clients. The old terms were prerelease-only, so no migration or compatibility aliases are needed.

* fix(gateway): preserve creator provenance filtering

Keep creatorId scoped to immutable createdActor provenance while ownerId queries the current projected assignable owner. This preserves independent creator and responsibility filtering after reassignment.

* test(ui): wait for remembered draft before reload

CI exposed an IndexedDB draft-persistence race: the test reloaded before the write completed and then re-filled the message while restoration arrived. Wait on the canonical durable-draft helper before reload so the reload cannot race the write.

* fix(ui): keep session menus clear of hovercards

Horizontal sidebar previews were positioned from the inner link rect instead of the complete session row, allowing the hovercard to overlap trailing actions.

Anchor preview placement to the full row while preserving the link trigger and ownership flow so the session menu remains clickable.

* perf(ui): keep hovercard fix within startup budget

Use the sidebar direct-row invariant to anchor the hovercard outside trailing actions without a selector lookup. This preserves the fix without increasing the startup budget.

* fix(qa): preserve Matrix CLI timeout precedence

Keep the primary timeout operator-visible when descendant settlement also reports secondary cleanup trouble. Preserve the complete AggregateError as the public wrapper cause so settlement evidence remains inspectable.

* test(ui): isolate Markdown table clipboard boundary

With isolate:false, the shared module registry can retain clipboard imports before this test installs its module mock, leaving the spy disconnected from the production call.

Stub navigator.clipboard.writeText instead so the test exercises the real copyToClipboard boundary regardless of module load order, then restore the original descriptor.
2026-08-18 03:07:21 -07:00
Peter Steinberger 6ed136b22d fix(ui): restore mock chat startup (#125729) 2026-08-18 02:02:31 -07:00
Peter Steinberger ad475ce33a feat(gateway/ui): command-lane diagnostics with debug page table and global busyness overlay (#125591)
* feat(gateway): expose command lane diagnostics

* feat(ui): add live debug busyness overlay

* fix(ui): show newest events in debug overlay and update diagnostics call-list tests

* test(ui): add lane and status fixtures to the mocked dashboard

* feat(ui): add System busyness entry to the account menu

* fix(gateway/ui): bound lane diagnostics, append-only descriptor, fail-visible lanes load

Addresses ClawSweeper review findings on #125591: diagnostics.lanes moves to
the append-only tail of the descriptor table, the Control UI lanes request
fails visibly instead of masking errors, and the RPC exports only static
lane snapshots plus a bounded dynamic-session aggregate composed in the new
command-lane-diagnostics module.

* chore(protocol): regenerate Kotlin gateway methods for diagnostics.lanes

* test(gateway/ui): register diagnostics.lanes in the 2026.8 train and mock it in the debug e2e
2026-08-18 01:10:32 -07:00
Peter Steinberger b5b17c654b fix: keep Workboard visible in the sidebar (#125473)
* fix(ui): keep workboard in sidebar navigation

* test(ui): align workboard navigation ownership

* fix(ui): preserve saved workboard sidebar slots

* test(ui): shrink assertion safety baseline

* fix(plugins): bind native routes to bundled owners

* refactor(plugins): isolate native route policy
2026-08-17 18:44:39 -07:00
Peter Steinberger b228c83bfc feat(dashboard): add session:progress board tile rendering the live progress card (#125438)
* feat(dashboard): add session:progress board tile rendering the live progress card

Advertise the core-owned widget kind via hello controlUiWidgetKinds at operator.read.
Render it inline without an iframe from the session-progress-cards store.
Pin it with dashboard tool widget_put using pluginKind session:progress and optional props.sessionKey.
Follow up the progress-card unification from #125125.

* fix(dashboard): surface session progress load failures

Record protected progress-card read failures in the shared per-session store.
Render an actionable board-tile error with retry instead of indefinite loading.
Cover the rejected-read and successful-retry flow at the widget boundary.

* fix(dashboard): honor progress tile access and activity

Avoid progress-card reads while a retained board is inactive.
Distinguish sharing denial from transient load failures and show the correct remedy.
Qualify cross-session pinning docs and cover activation plus denial behavior.
2026-08-17 16:56:23 -07:00
Peter Steinberger de9b367214 fix(ui): generic mock chat sends show a visible outcome (#125347)
* fix(ui): make generic mock chat sends observable

* test(ui): stabilize control UI e2e timing
2026-08-17 11:40:56 -07:00
Peter Steinberger 2915e563d6 feat(workboard): show full boards on session dashboards (#125094)
* feat(workboard): full-board dashboard widget

Adds a third trusted plugin widget kind, workboard:board, rendering the
complete Kanban board (all columns, live plugin.workboard.changed
refresh) inside a session dashboard. Props {boardId} scope it to one
board; without it the widget shows every board, matching workboard:mini
semantics. Card rendering reuses the workboard page renderColumn with an
explicit surface option so page and widget cannot drift; the shared
board filter moved to ui/src/lib/workboard/board-filter.ts. Mutations
follow the connection's canMutate; read-only connections get a
view-only board.

Proof: pnpm test ui/src/lib/board ui/src/pages/workboard
ui/src/lib/workboard extensions/workboard (9,494 passed), i18n baseline
green, autoreview clean (codex/gpt-5.6-sol). tsgo core/ui/extensions
green locally; remote check:changed blocked by Daytona capacity and the
tsgo:core Daytona exit reproduced locally as a heavy-check lock race,
passing on retry.

* test(ui): seed workboard fixtures in the mocked dev server

* fix(ci): register workboard proof capture script
2026-08-16 23:19:30 -07:00
Peter Steinberger fa642a305e fix(ui): drop duplicate plan card summary (#124895) 2026-08-16 16:45:23 -07:00
Peter Steinberger 68762ad22c fix(ui): give queued-outbox badges their own outbox icon (#124842)
The sidebar queued-message badge and the composer queue reused the clock
glyph that also marks attached automations, so a session with both showed
two identical clocks distinguishable only by tooltip. Add an outbox tray
icon (Lucide inbox with the roof swapped for a rising arrow) and use it
for queued-to-send surfaces; the clock stays automation/cron-only. The
mock dev fixture now flags one session with hasAutomation so the badge
renders in mocked-dashboard proofs.
2026-08-16 14:29:41 -07:00
Ayaan Zaidi 1425d944ca fix(ui): show Claude Code logo in mock Control UI sidebar (#123496)
The mock catalog used id claude-code, but the sidebar only brands registered plugin ids (claude).
2026-08-14 05:37:33 +00:00
Peter Steinberger 9415181b75 fix(ui): make active visibility pill distinct from its hover state (#123173)
* fix(ui): make active visibility pill distinct from its hover state

* test(ui): advertise sessions.create in the control-ui mock harness

* ci: refresh pull_request run after zombie-queued Blacksmith jobs
2026-08-13 12:42:40 -07:00
Peter Steinberger 6f39f953ec fix(ui): show each chat panel button once, in the pane header (#122507)
* test(ui): advertise terminal and browser panels in the mock harness

The mocked Control UI never advertised browser.request or terminal.open and
left terminalEnabled false, so the chat header's panel toggles were invisible
in the harness and could not be visually verified.

* fix(ui): give the chat pane header the only panel toggle row

The session workspace rail header rendered Terminal, Browser, Ask OpenClaw and
Changes alongside its own dock/refresh/collapse controls. Terminal and Changes
already lived in the chat pane header, so both rendered twice at once, while
Browser was reachable only from inside a files rail and Ask OpenClaw sat in a
per-session rail despite being a global surface that already owns a sidebar
entry (settings route 'custodian').

The rail header now owns workspace-file actions only. Browser moves up to the
pane header beside Terminal and into the narrow-header overflow menu; the
duplicated Terminal and Changes buttons and the Ask OpenClaw toggle are gone.

Production LOC: +21 -84.

* test(ui): stop the vite stub from shadowing the mock bootstrap config

ui/vite.config.ts registers a placeholder /control-ui-config.json middleware
and config-file plugins load before inline ones, so the mock gateway plugin's
bootstrap body never reached the app and every scenario bootstrap field was
silently dropped. Marking the mock plugin 'pre' lets it answer first.
2026-08-12 00:13:13 -07:00
Peter Steinberger ee7fae8a90 fix(ui): native command settings no longer require Raw mode (#121832)
* fix(ui): render native command settings controls

Render boolean-or-auto command settings as safe On/Off/Auto controls instead of forcing Raw mode, while preserving typed config values and fail-closed handling for unsafe unions.

* fix(ui): preserve oneOf union exclusivity
2026-08-10 21:28:06 -07:00
Peter Steinberger b81946d6af fix(ui): make Cloud Worker startup responsive (#121200)
* fix(openai): filter platform-only ChatGPT catalog rows

* fix(ui): show Cloud Worker startup progress

* fix(ui): keep cloud startup out of app bootstrap

* fix(ui): reduce cloud startup bootstrap cost

* fix(ui): satisfy cloud startup lint

* fix(ui): keep cloud startup within UI limits

* fix(ui): satisfy cloud startup CI limits

* fix(ui): isolate concurrent cloud startup

* fix(ui): address cloud startup review findings

* fix(ui): persist cloud startup recovery per session

* style(ui): format cloud startup chat props
2026-08-09 22:42:45 -07:00
Patrick Erichsen d4c3b9e783 refactor(sessions): remove custom icon feature (#121263)
* refactor(sessions): remove custom icon feature

* test(sessions): expect legacy icons to be stripped

* fix(gateway): preserve retired icon request compatibility

* chore(plugin-sdk): refresh API baseline

* fix(plugins): reserve retired session icon slot
2026-08-10 04:51:56 +00:00
Vyctor H. Brzezowski 45da07ed20 improve(ui): align session context menu rows, icons, and shortcut hints (#121383)
Menu rows stacked Web Awesome's shadow icon margin on top of our flex gap
(~17px gutter), let the icon slot baseline-align ~2px above the label centre,
drew shortcut hints at 550 weight beside 400-weight labels, and left the submenu
chevron 4px inside the hint column at a heavier size.

Rows now use a single icon column, optically centred icons, quiet mono keycap
hints on one rail, a chevron sharing that rail, and a divider inset to the same
columns. The control UI mock harness also advertises the session mutation
methods so the menu renders enabled instead of fully disabled.
2026-08-10 01:18:35 -03:00
Peter Steinberger ea50fe8453 fix(ui): open mock catalog sessions without crashing (#120444) 2026-08-07 23:21:54 -07:00
Peter Steinberger faf2602d22 fix(ui): keep native context menus out of the sidebar and make session catalogs hideable (#118217)
* fix(ui): keep native context menus out of the sidebar and make session catalogs hideable

Suppress the WKWebView default context menu across the sidebar while preserving editable inputs, and route agent cards and session-catalog headers to the existing menus. Persist hidden session sections in localStorage and expose live-synced Show controls under Settings → Appearance → Sidebar.

Co-authored-by: Codex <codex@openai.com>

* test(ui): serve mock session catalogs so the sidebar catalog sections are exercisable in dev:ui:mock

Advertises sessions.catalog.list and returns synthetic Codex/Claude Code
catalogs, enabling reproducible live proof of the catalog header context
menu and hide/restore preference flow.

Co-authored-by: Codex <codex@openai.com>

---------

Co-authored-by: Codex <codex@openai.com>
2026-08-02 16:02:53 -07:00
Vincent Koc 1065c1d697 fix(ui): identify source builds in settings footer (#116134)
* fix(ui): identify source builds in settings footer

* fix(release): classify all official Control UI builds
2026-07-30 08:58:34 +08:00
Peter Steinberger d885f9175d feat(ui): move settings save feedback into the sidebar footer (#115679)
* feat(ui): move settings save feedback to sidebar

* test(ui): support stateful config writes in mock gateway

* test(ui): add save indicator to memory sidebar test
2026-07-29 04:10:56 -04:00
Peter Steinberger 6fbaa4d232 ui: complete contextual Settings documentation links (#115665)
* feat(config): require docs decisions for root settings

* feat(ui): link settings pages to guides

* refactor(ui): keep model providers page compact

* fix(ui): style page subtitles and carry base hints in mock dev
2026-07-29 03:35:28 -04:00
Peter Steinberger 7a1aa4eb4f feat(ui): Talk settings page with catalog-driven realtime pickers (#115409)
* feat(talk): emit realtime models and voices in talk.catalog and mirror create-time readiness

* feat(ui): add curated Talk settings page with catalog-driven pickers

* docs(talk): correct stale claims and add one-page GPT-Live setup path

* fix(ui): refresh Talk catalog on config-hash advance and neutralize GPT-Live badge

* fix(ui): provider-aware Talk selection, atomic provider switch, focus refresh

* fix(ui): resolve Talk provider fallbacks via catalog and make Default a true reset

* fix(ui): provider-compatible transports and race-free Talk catalog loads

* fix(ui): never resolve an unknown explicit Talk provider to the active one

* docs(talk): note Android relay readiness caveat for browser-only models

* fix(ui): keep the relay transport when switching Talk provider to Auto

* fix(ui): align section-ownership test and drop unused export after rebase
2026-07-28 17:38:15 -04:00
Peter Steinberger 699315e7d7 feat(ui): redesign Ask OpenClaw — mascot, shared surface, dockable panel (#115123)
* refactor(ui): share custodian chat surface

* feat(ui): add dockable custodian panel

* refactor(ui): drop write-only panel-close latch from custodian store

* feat(ui): demo custodian in mock gateway

* chore(ui): update raw-copy baseline for custodian strings

* fix(ui): clean custodian surface/page/mock lint debris
2026-07-28 08:05:38 -04:00
Peter Steinberger add9205d1a fix(ui): explain every channel setting and link its docs (#114844)
* feat(config): give shared channel settings help text

* fix(ui): space the settings tiers and stop repeating help on list items

* feat(ui): link each channel detail to its docs page

* test(ui): mirror production channel hints in the mock dev server

* docs: note the shared channel help inheritance for plugin authors

* fix(config): let a channel suppress shared help with an empty string

* chore(config): regenerate bundled channel metadata for the new WhatsApp hints

* fix(ci): check bundled channel metadata locally

* chore(release): keep changelog release-owned

* chore(release): keep changelog release-owned

* fix(ui): keep shared channel help contract-neutral
2026-07-28 05:25:58 +00:00
Peter Steinberger fbb3525368 fix(ui): show a simple channel settings view with a flip to advanced (#114741)
* test(ui): make channel settings renderable in the mock dev server

* fix(ui): hide advanced channel settings behind the shared advanced tier

* fix(ui): widen the tier renderer callback to lit's nothing

* fix(ui): keep the advanced collapse control on advanced-only channel forms

* docs: note the shared advanced tier on channel settings
2026-07-27 16:39:23 -04:00
Peter Steinberger 762f04da5a refactor(ui): redesign channels DM access requests, drop channel-health JSON card (#114717)
* feat(ui): serve DM pairing fixtures from the mock dev harness

* refactor(ui): align channels DM access requests with the settings design language and drop the channel-health JSON card
2026-07-27 16:15:54 -04:00
Peter Steinberger f23928e418 fix(ui): keep channel action labels on one line and surface QR next to actions (#114708)
* fix(ui): keep channel action labels on one line and surface QR next to actions

* fix(test): drop duplicate prewarm test from attempt-extra shard config
2026-07-27 15:55:38 -04:00
Peter Steinberger fa2b84697b feat(dev): add cron fixtures to the Control UI mock server (#114248) 2026-07-26 23:08:22 -04:00
Peter Steinberger c59d38138e fix(scripts): make the mock Control UI exec approval opt-in via --fixture=approval (#114246) 2026-07-26 23:06:03 -04:00
Peter Steinberger f90cef67c8 feat(ui): drag custom sidebar groups between built-in session zones (#113948)
* feat(ui): drag custom sidebar groups between built-in session zones

* test(ui): remove stale split ratio fixture

* perf(ui): raise startup budget baseline for session-section ordering pref
2026-07-25 19:11:25 -07:00
Peter Steinberger ce5ab8adb8 refactor(gateway): remove dead sessions.observer.ask rpc (#113791)
* refactor(gateway): remove dead sessions.observer.ask rpc

* docs: record btw and companion contract split

* fix(gateway): unexport observer model sanitizer after ask removal
2026-07-25 14:44:02 -07:00
Peter Steinberger 421e287c45 fix(ui): show Swarm progress in Chat (#113619)
* fix(ui): show Swarm progress in chat

* style(ui): format rebased Swarm integration

* fix(ui): bound inline Swarm progress height
2026-07-25 04:36:50 -07:00
Peter Steinberger fc92b9fd91 feat(ui): merge creator avatar into sidebar leading slot, move creator filter into Threads menu (#113150)
* feat(ui): merge creator avatar into sidebar leading slot and move creator filter into Threads menu

The per-row creator chip previously rendered next to the leading state
indicator, so rows with a known creator started their titles at a
different x-offset than rows without one. The avatar now occupies the
single fixed leading slot: unread renders as a corner badge on it,
running as a spinner ring, and open/merged PR state as a colored corner
badge, while attention and pinned icons keep the slot. Child rows keep
their status badges and no longer render owner chips.

The standalone 'Filter by creator' select above the session list is
gone; the Threads funnel menu gains a People radio section with owner
chips, and the funnel trigger shows an accent dot while a creator
filter is active. The empty Threads header stays visible when ownership
chrome is active so the filter can always be cleared. Mock dev fixtures
gain two creator identities so the ownership chrome is demonstrable.

* test(ui): guard parent row spread in child-avatar ownership case
2026-07-23 15:26:56 -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 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 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 025e6ceee0 fix(ui): theme board fixture dropdowns (#111998) 2026-07-21 07:22:16 -07:00
Peter Steinberger a370785bab fix(ui): populate mock profile identity (#112296) 2026-07-21 05:55:46 -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 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
Peter Steinberger 94b3345623 improve(ui): unify new-thread folder and where pickers into one place picker (#112035)
* improve(ui): unify new-thread folder and where pickers into one place picker

The new-thread draft asked for one decision (where does this thread run)
through two chips with separate popovers, a dead-end target-list panel
with a disabled back button, and a machine menu that rendered even when
the Gateway was the only choice. One chip now carries the (destination,
folder) pair; its popover stacks a root menu (workspace, recent places
derived from the session list, browse, places, worktree) over the folder
browser, back and Escape pop one level, and the destination axis only
appears when there is a real choice or an existing selection.

* fix(ui): give recentPlaces a production consumer module for the knip gate

Knip's production scan rejects test-only exports; the recents derivation
moves to recent-places.ts, imported by the place picker, and the unit
test follows it.

* fix(ui): drop stale place-picker.test.ts left behind by the rename
2026-07-20 22:00:33 -07:00
Peter Steinberger e2e394e1ab fix(ui): give roster rows their avatar-text gap and add presence mock fixtures (#111689)
* fix(ui): add avatar-text gap in roster menu and presence mock fixtures

* refactor(ui): keep presence snapshot helper out of the connect auth hunk
2026-07-19 23:38:40 -07:00
Peter Steinberger 40d31f3481 feat(control-ui): show relative commit age and hover-only copy button on About (#111495)
The About page commit row now embeds the commit's committer timestamp
(commitAt, advisory like branch/dirty) and renders it as an always-relative
age with the exact localized date-time on hover. The copy button becomes a
compact borderless icon revealed on hover/focus only where hover exists;
touch keeps it visible.
2026-07-19 11:13:25 -07:00
Peter Steinberger 3a5da4faa8 feat(ui): live agent activity subtitles on running sidebar sessions (#111221)
* feat(ui): live agent activity subtitles on running sidebar sessions

* refactor(ui): lazy-load narration controller off the startup chunk, unexport test-only symbols

* chore(ui): raise startup JS budget to 312 KiB for the lazy narration feature

* test(ui): restore real timers after narration controller cases
2026-07-19 01:08:06 -07:00
Peter Steinberger 6c2973dee4 feat(ui): automatic session attention states in the sidebar (#111035)
* feat(ui): automatic session attention states in the sidebar (question, approval, failed run)

* test(ui): split attention presentation and read-marker cases under line budgets

* fix(ui): restore precise chat-pane test-support signatures
2026-07-18 17:43:59 -07:00