Commit Graph

256 Commits

Author SHA1 Message Date
Vincent Koc fd28cd3bec fix(ui): support shortcuts on non-Latin keyboards 2026-07-29 23:09:22 +08:00
batmanscode f3b70d5902 fix(ui): include proxy credentials in manifest requests (#111053)
* fix(ui): include credentials in manifest requests

* test(ui): verify authenticated PWA manifest browser requests

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-29 08:10:36 -04:00
xydigit-sj 7b34145e44 fix(ui): fall back to updateAvailable.latestVersion for handoff version verification (#112987)
* fix(ui): derive pending update expected version from updateAvailable fallback

* test(ui): verify managed update handoff after reconnect

* style(ui): format managed handoff browser regression

* test(ui): align managed update verification with gateway phases

* fix(ui): keep skill workshop within the mobile viewport

* test(ui): await sidebar route readiness after reload

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-29 07:28:14 -04:00
Peter Steinberger f318df7a55 refactor(ui): dissolve the General settings page into Appearance (#115798)
* refactor(ui): dissolve the General settings page into Appearance

* test(ui): drop dissolved config route expectation

* test(ui): cover legacy General model redirect

* style(ui): format legacy redirect test
2026-07-29 05:49:20 -04:00
Vincent Koc 25c375e47f refactor: reuse canonical record guards (#115810)
* docs(agents): standardize canonical record guards

* refactor(model-catalog): use canonical record guard

* refactor(scripts): use canonical record guard

* refactor(ui): use canonical record guard

* refactor(codex): use canonical record guard

* refactor(agents): use canonical record guard

* refactor(sessions): use canonical record guard

* refactor(doctor): use canonical record guard

* refactor(infra): use canonical record guard
2026-07-29 11:43:36 +02:00
Vincent Koc 755eea5e97 fix(ui): localize remaining control surfaces (#115730)
* feat(ui): add localization keys for control surfaces

* fix(ui): localize relative time and durations

* fix(ui): localize update and recovery notices

* fix(ui): localize chat controls and command results

* fix(ui): localize memory management views

* fix(ui): localize shared tool surfaces

* fix(ui): localize settings and action notices

* chore(ui): tighten localization raw-copy baseline

* fix(ui): preserve localized status copy

* fix(ui): preserve compact sidebar time label

* fix(ui): preserve near-future sidebar direction

* test(ui): align screenshot localization assertion
2026-07-29 16:34:35 +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 ac7154eeb4 fix(ui): give Memory settings path-based tab URLs (#115515)
* fix(ui): add path-based memory tab URLs

* chore: remove release-owned changelog entry
2026-07-29 00:12:09 -04:00
Kagura d53261360f fix(agents): use lastSeenAtMs tie-break in canvas default-node selection (#112084)
* fix(agents): use lastSeenAtMs tie-break in canvas default-node selection

When multiple nodes share the same connectedAtMs (or are all disconnected),
the comparator now checks lastSeenAtMs before falling through to the stable
nodeId alphabetical ordering. This prevents the canvas from selecting a stale
node that was connected long ago but has since been replaced by a more recently
active device.

* fix(nodes): harden offline canvas target selection

Co-authored-by: Kagura <kagura.chen28@gmail.com>

* fix(nodes): keep offline target fix release-ready

Co-authored-by: Kagura <kagura.chen28@gmail.com>

* fix(nodes): ignore stale connection times offline

Co-authored-by: Kagura <kagura.chen28@gmail.com>

* test(ci): stabilize startup and memory UI assertions

* test(gateway): inject prepared manifest metadata

* test(gateway): isolate startup model log coverage

* test(gateway): reuse prepared model manifests

* test(ui): keep startup abort fixture cold

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-28 19:49:15 -04:00
Peter Steinberger d239a59d82 fix(ui): make Control UI ownership and permissions reliable (#115364)
* fix(ui): unify connection-owned gateway event dispatch

* fix(qa): keep hosted UI smoke evidence truthful

* fix(ui): make mobile navigation drawer an accessible modal

* refactor(ui): centralize settings search destinations

* fix(ui): own chat media resource lifecycles

* fix(ui): unify sidebar session scope ownership

* refactor(ui): remove obsolete navigation backdrop styles

* refactor(ui): isolate dashboard provider lease capabilities

* fix(ui): centralize gateway operator permissions

* style(ui): format gateway event regressions

* fix(ui): render live dashboard permissions immediately

* fix(ui): enforce approval grant authority

* fix(gateway): fence retired sockets after event gaps

* fix(ui): isolate sidebar gateway fixtures across shared workers

* test(ui): isolate singleton-sensitive browser suites

* fix(ui): retire stale catalog pagination on gateway reconnect

* fix(ui): restore drawer focus after native dialog dismissal

* fix(ui): seed drawer threads and preserve modal focus ownership

* fix(ui): isolate nested native drawer overlay lifecycle

* test(ui): prove isolated dashboard lease authorization

* fix(ui): bound settled managed image resources

* fix(ui): type native modal focus and shared test helper

* fix(ui): correct approval mock types and trim dead export

* fix(ui): keep settings section metadata private

* fix(qa): keep hosted coverage regression within lint limit

* refactor(ui): keep catalog presence in its session data owner

* fix(browser): regenerate bundled copilot runtime

* test(ui): split board lease authorization regressions

* fix(ui): snapshot gateway listener fanout without redundant spread

* fix(ui): bind chat media subscriptions to image lifetime

* fix(ui): extract overlay access lifecycle

* fix(ui): restore guarded media after Lit reconnection

* test(ui): localize board lease fixture title

* fix(ui): reuse system approval fixture labels

* test(ui): narrow managed media lifecycle source

* fix(ui): prevent retired board gateway clients from rolling back leases

* fix(ui): expose pairing to pairing-scoped operators

* fix(ui): preserve legacy device pairing access

* fix(ui): preserve responsive sidebar ownership

* fix(ui): preserve responsive navigation and prove media ownership

* fix(ui): retire revoked catalog and refresh pairing grants

* test(ui): align typed catalog fixtures with main
2026-07-28 16:42:05 -04:00
Peter Steinberger c475209abc fix(ui): keep explicit navigation ahead of chat canonicalization (#115366)
* fix(ui): preserve navigation during chat canonicalization

* refactor(ui): extract chat canonicalization ownership

* style(ui): keep chat page within line budget

* refactor(ui): trim chat page layout helpers

* style(ui): format canonicalization changes
2026-07-28 15:39:19 -04:00
Peter Steinberger 58a3679c49 fix(ui): keep reconnects, browser tabs, and localized search consistent (#115221)
* fix(ui): fence stale gateway and browser lifecycles

* test(ui): restore history after agent tool navigation
2026-07-28 11:24:02 -04:00
Peter Steinberger 4eab19a25d fix(ui): stop route aliases from hijacking base-path inference on settings deep links (#115186) 2026-07-28 08:51:26 -04:00
Peter Steinberger 0cb56ace62 fix(ui): harden browser, session, permissions, and media lifecycles (#115110)
* fix(ui): harden browser, session, and gateway lifecycles

* fix(ui): satisfy browser lifecycle and control UI CI gates

* fix(ui): satisfy type-aware browser and cron lint

* fix(ci): isolate model and UI test workloads

* fix(ui): reject superseded browser and session page races

* fix(ui): settle superseded background-tab refreshes

* fix(ui): reconcile committed navigation and terminal pages

* fix(ui): preserve canonical cron permission contracts
2026-07-28 05:48:35 -07: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 7f37900bca perf(ui): flip sessions instantly and drop redundant switch RPCs (#115129)
* perf(ui): flip sessions instantly and drop redundant switch RPCs

* chore: revert changelog edit (release generation owns CHANGELOG.md)

* test(ui): adapt ported switch e2e tests to split-suite helpers

* chore(ui): un-export internal CachedShortSession type (knip)
2026-07-28 06:25:25 -04:00
Peter Steinberger 31ad055259 fix(ui): avoid restart prompt when toggling advanced settings (#114937)
* fix(ui): keep advanced disclosure browser-local

* chore: leave changelog to release flow
2026-07-28 01:17:40 -04:00
Peter Steinberger a5ee5039ce test(ui): split the oversized Control UI e2e suites (#114889)
* test(ui): split oversized Control UI e2e suites

* test(ui): bound new-session locator polling

* test(ui): fix split e2e metadata

* test(ui): give startup waits an explicit budget
2026-07-28 01:07:21 -04:00
Peter Steinberger a0530259e2 fix(ui): preserve navigation during startup (#114828) 2026-07-27 23:00:04 -04:00
Peter Steinberger b12f631a4a fix(ui): keep Gateway questions isolated across reconnects (#114794) 2026-07-27 19:35:09 -04:00
qingminlong 15ab1334f4 fix(ui): clear web push ready timeout (#110879)
* fix(ui): clear web push ready timeout

* fix(ui): clear web push ready timeout

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-27 18:07:21 -04:00
Peter Steinberger 1c0ccdddcd fix(ui): hide the terminal dock while Settings is open (#114737)
* fix(ui): hide docked terminal and browser panels during settings takeover

* test(ui): align browser panel casts with core test typecheck

* test(ui): split dock suppression coverage
2026-07-27 17:08:52 -04:00
Peter Steinberger 7e25a84484 fix(ui): show resolved avatars on session owner chips (#114682)
* fix(ui): show resolved avatars on session owner chips

* chore(ui): drop unused ActorIdentityUser re-export
2026-07-27 15:15:18 -04:00
Peter Steinberger 3d03c415d1 test(ui): remove two load-dependent flakes in the Control UI suite (#114585)
* test(ui): remove two load-dependent flakes in the Control UI suite

Both failed only under a saturated worker pool, roughly one full run in four.

The board refresh tests asserted a 1ms boundary (nothing at 4999ms, fired at
5000ms) on a timer armed during a render cycle, so any drift in when it was
armed failed them. Assert the band that carries the meaning instead: silent at
2s rules out the 1s floor, fired by 8s rules out the 15s a full-TTL calculation
would give. Call count is no longer pinned because the unreplaced ticket keeps
retrying, which has its own test.

The router outlet settled by pumping a fixed five cycles, which returns while a
chain is still resolving into another render. Drain to Lit's documented settled
state instead, via a shared helper with its own coverage.

* test(ui): keep a drain floor so settling never regresses the fixed pump

A settled update only says that render did not reschedule itself, so a promise
chain that requests an update at its end can still be in flight. Keep the five
turns unconditionally and let the settled check extend past them.

* docs(test): state the settle helper's bound instead of implying quiescence
2026-07-27 09:17:33 -04:00
Peter Steinberger c56689416e fix(ui): scope global route resolution by agent 2026-07-27 05:43:19 -04:00
Peter Steinberger f8a3023a46 fix(ui): preserve agent selection across reconnects 2026-07-27 05:43:19 -04:00
Peter Steinberger 51f228f6fe fix(ui): preserve agent-owned session navigation
Add agent ownership to observer digests, scope global observer delivery and reconciliation, and centralize application session selection across navigation and reconnects.

Co-authored-by: xbrxr03 <abrarhabib03@gmail.com>
2026-07-27 05:43:19 -04:00
Peter Steinberger 9f509d4923 refactor(ui): consolidate chat and security regression fixtures (#114408)
* refactor(ui): consolidate chat and security regression fixtures

* fix(ui): type metadata regression fixtures structurally

* fix(ui): remove obsolete realtime test lint suppression

* fix(ui): preserve grandfathered realtime test lint invariant
2026-07-27 05:42:11 -04:00
Peter Steinberger 4f0dcd4d30 fix(ui): show centered mascot while pages load (#114481) 2026-07-27 05:40:38 -04:00
Peter Steinberger a2ff6cb52b fix(ui): consistently load and cache user avatars (#114444)
* fix(ui): consistently load and cache user avatars

* fix(ui): retain avatar images across profile updates
2026-07-27 05:00:58 -04:00
Peter Steinberger af552d4bc6 feat(ui): resolve session URLs through the gateway with best-effort slug matching (#114422)
* feat(ui): resolve session URLs through the gateway with best-effort slug matching

Session URLs now resolve a stored board face and a display-name slug through
the gateway instead of guessing from the browser's cached session page.

- An uncached open marks only the in-app navigation, never the shareable href,
  so the chat loader can re-derive the face and replace the URL.
- A cached row settles the lookup locally, keeping navigation off the wire.
- A one-segment reference resolves short id, then literal key, then display-name
  slug; ties reuse the existing disambiguation view.

* refactor(ui): keep slug ties on short disambiguation prefixes

Slug candidates reused the full uuid, which produced 32-character links in the
disambiguation view. uniqueShortIdPrefix already falls back to the full id when
the bounded search was truncated, so reuse it and drop the flag.

* fix(ui): navigate worktree owner links in-app so the face marker survives

The Worktrees owner link was a bare anchor consuming only the shareable href,
so preferenceDerivedFace was a no-op there and an uncached owner always opened
on chat. Match the other session surfaces: keep the clean href and navigate
with the options on plain clicks.

* fix(ui): search the first uuid block so long session references resolve

The gateway matches sessions.list search as a plain substring and stored keys
hold a hyphenated uuid, so any hyphen-stripped reference past the first block
matched nothing and 404'd. This hit disambiguation links, which offer prefixes
longer than eight characters. Send the first block and keep applying the full
prefix per row.

A resolved slug now canonicalizes to that same short reference instead of a
full uuid, so /chat/main/deploy-monitor settles on -6db92d48.

* docs(ui): record why the face marker stays out of shareable hrefs
2026-07-27 04:31:33 -04:00
Peter Steinberger 24e6d5edd7 fix(ui): recover offline-selected locales once the gateway reconnects (#114378)
* fix(ui): retry offline-failed locale loads when the gateway reconnects

* fix(ui): recover offline-failed locale loads via guarded stale-chunk reload

* test(ui): isolate locale retry tests from the i18n singleton cache

* test(ui): move locale manager test factory to test-support
2026-07-27 03:18:02 -04:00
Peter Lee 0406e66369 fix(ui): keep stable chat rows in insertion order and only sort live tool/stream items by timestamp (#113266)
* fix(ui): keep stable chat rows in insertion order and only sort live tool/stream items by timestamp

* fix(ui): keep live rows within current turn

* fix(ui): keep current work above queued turns

* fix(ui): keep streamed replies above queued turns

* fix(ui): preserve reconnecting run order

* fix(ui): preserve causal terminal ordering

* fix(ui): bound replay rows to owning turns

* fix(ui): keep question summaries in owning turns

* fix(ui): scope question run ownership to session

* fix(ui): restore reconnecting chat run identity

* fix(ui): remove unused chatItemTimestamp import in chat-thread-build.ts

* fix(ui): correlate question summaries with agent runs

Co-authored-by: Peter Lee <li.xialong@xydigit.com>

* chore(i18n): refresh native source baseline

Co-authored-by: Peter Lee <li.xialong@xydigit.com>

* fix(ui): remove unused chatItemTimestamp export and split tool-stream test file

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-27 02:08:22 -04:00
Peter Steinberger e78310fc23 fix(ui): validate session catalog agent (#114303) 2026-07-27 01:33:08 -04:00
Peter Steinberger e0eed257c8 fix(ui): persist Control UI settings across reconnects via gateway-owned LWW prefs writes (#114286)
* fix(ui): sync Control UI prefs via hash-free LWW config.patch

* test(ui): prove prefs reconnect replay end to end

* fix(gateway): surface hash-free prefs commit races instead of replaying stale intent

* fix(ui): never re-reconcile a retained config snapshot over acked prefs

* fix(ui): merge persisted pending prefs across tabs instead of clobbering

* test(ui): pass current runtime config through sidebar prefs reconcile fixture
2026-07-27 01:17:03 -04:00
Peter Steinberger 8b66fc103d feat(ui): durable session board face and dashboards index (#114262)
* feat(ui): durable session board face and dashboards index

Board face lived only in client-side boardSessionViews, capped at 50 entries,
so the preference never followed the user to another device, evicted as
sessions accumulated, and could not be seen as a set.

Persist it as SessionEntry.boardFace, which rides the existing entry_json blob
and so needs no SQLite schema change or version bump. Expose it on the session
list row and add it to the sessions.patch write-scope allowlist alongside label,
pinned, and archived: setting your own view preference is user-level chat
organization, not policy. Unknown patch fields still fail closed to
operator.admin.

Generic navigation now reads the stored face, so the sidebar and session list
open a thread on the face you left it on. boardSessionViews keeps only
activeTabId and reopenDockByTab, which are genuinely per-device.

Add /dashboards listing threads whose preferred face is dashboard. Filtering
runs server-side in filterSessionEntries before pagination, because the client
holds only a capped page and a client-side filter would silently omit
dashboards.

* test(protocol): assert the pre-rename face param is rejected

The gateway-protocol validator test still passed the pre-rename 'face' key,
which the closed schema rejects. Use boardFace, and pin the old name as a
negative case so it cannot silently return.

* chore(protocol): regenerate Swift bindings and docs map for boardFace

Adding boardFace to the sessions schema changes two committed generated
artifacts: the Swift gateway models (pnpm protocol:gen:swift) and the docs map
(pnpm docs:map:gen), which now lists the dashboards index section.
2026-07-27 00:35:34 -04:00
Peter Steinberger bb55d44840 fix(gateway): stop fabricating assistant agent id "main" before roster resolution (#114257)
Three fabrication points told clients the assistant agent was "main" before
any roster/config resolution: DEFAULT_ASSISTANT_IDENTITY in
src/gateway/assistant-identity.ts, the Control UI store's initial snapshot
(ui/src/app/gateway-store.ts:65), and its hello fallback (:336). On installs
whose implicit main agent is retired, every page reload fired
sessions.catalog.list for the nonexistent agent and flashed
'unknown agent id "main"' in the sidebar.

The no-roster state now carries no agent id: DEFAULT_ASSISTANT_IDENTITY drops
agentId, resolveAssistantIdentity returns ResolvedAssistantIdentity (agentId
required) for config-backed paths, the bootstrap omits the optional
assistantAgentId field without config, the UI store starts null, and agent
selection adopts the roster default once agents.list arrives.
2026-07-26 23:48:13 -04:00
Peter Steinberger cca5b14785 feat(ui): path-based session and dashboard URLs (#113883)
* feat(ui): path-based session and dashboard URLs

* docs(ui): document control UI URLs

* fix(ui): finalize session path routing

* feat(ui): anchor session URLs on stable keys

* docs(ui): clarify stable session URL identity

* fix(ui): resolve session prefixes with full prefix and pagination

Query sessions.list with the full supplied prefix instead of an eight-char
truncation, and paginate up to a bounded page count so longer disambiguation
links resolve instead of being reported ambiguous. Zero strict-prefix matches
now fall through to literal-key resolution rather than rendering an empty
ambiguity view.

Also document the ~dot/~dotdot segment escape: peer ids reach session keys
trimmed and lowercased only (src/routing/session-key.ts), so a literal '.' or
'..' segment is reachable and browsers would normalize it away.

* fix(ui): synchronize committed session routes

* test(ui): split native shell host coverage

* fix(ui): thread configured mainKey through session URL builders

Reserved-set disambiguation needs the operator-configured mainKey at runtime, so
thread it from agentsList through every session path builder and the ClickClack
control URL. Unambiguous non-hex single-segment rests now resolve literally while
short-id-shaped rests still fail closed, which restores ClickClack channel
compatibility detection and control-link reconciliation.

Also bound prefix-resolution retries, preserve catalog thread identity, and keep
draft state on ambiguous candidate links.

* fix(ui): repair session URL CI integration

* perf(ui): lazy-load session route resolution

* perf(ui): isolate session prefix resolution

* perf(ui): defer session path parsing

* perf(ui): defer session navigation startup

* fix(ui): preserve first-run and literal session navigation

* fix(ui): satisfy session routing type and export gates

* fix(clickclack): preserve unscoped control link agent

* style(ui): satisfy chat page line limit

* refactor(ui): move chat page helpers to owning modules

* fix(ui): preserve destination session route identity

* fix(ui): preserve agent identity in session routes

* fix(ui): escape dots in literal session path segments

encodeURIComponent leaves periods intact, so a literal key segment like
channel:release.js produced /chat/main/channel/release.js. In-app navigation is
intercepted by the SPA, but a refresh, an external link, or a ClickClack link
would be served as a static asset request and never reach the app.

pathForWorkboardBoard already escapes dots for this reason; mirror it in both the
session URL contract and the ClickClack encoder, route the agent id through the
same segment encoder, and pin the case in both shared vector tables.

* fix(ui): stop bootstrap after teardown race

* refactor(ui): centralize session navigation targets

* fix(ui): consume bootstrap teardown abort

* fix(ui): canonicalize configured main session routes

* fix(ui): preserve distinct session references

* fix(ui): redirect released session query links

* fix(ui): make bootstrap teardown abort-safe
2026-07-26 12:46:04 -04:00
Peter Steinberger 8eafae4af7 fix(ui): recover from unknown selected agents and surface session-catalog failures (#114048)
* fix(ui): recover from unknown selected agents and surface session-catalog failures

* test(ui): split catalog request-error cases under max-lines
2026-07-26 02:42:59 -04:00
Peter Steinberger 1677058cf5 fix(ui): keep first prompt across gateway reconnects (#114042) 2026-07-26 01:46:56 -04:00
Peter Steinberger 2de58d408a Control UI: gateway-owned sidebar section order (#113930)
* feat(ui): gateway-owned sidebar section order with hover-only drag grips

* fix(ui): repair sidebar section order CI gates

* fix(protocol): keep sectionOrder optional for older gateways

Native Swift clients ship separately from gateways, so new clients must decode older gateway responses that omit sectionOrder.

* fix(ui): reconcile gateway section ordering with main

* fix(state): allow lazy tables in v5 maintenance

* refactor(ui): retire prefs session section order in favor of gateway-owned order

Supersedes #113948 by deleting the unreleased ui.prefs.sessionSectionOrder key and its browser plumbing. Gateway SQLite sidebar_sections remains the single canonical store.
2026-07-26 01:15:19 -04:00
Peter Steinberger adfb59c19b feat(mac): dashboard gateway picker with in-place switching (#113965)
* feat(mac): add dashboard gateway switching

* feat(ui): add dashboard gateway picker

* docs(mac): document dashboard gateway picker

* fix(mac): harden gateway switching after review

* fix(ui): refresh gateway picker snapshots

* fix(mac): carry TLS pins through promotion and serialize gateway switches

* style(ui): satisfy lint rules in gateway picker files

* fix(ui): tolerate absent context in gateway picker pane props

* chore(ci): refresh generated inventories

* style(mac): satisfy Swift CI checks

* refactor(mac): drop dead GatewayEndpointStore.requireConfig

* perf(ui): own gateway capability in the chat chunk

* chore(ui): keep gateway capability factory module-private
2026-07-25 20:57:28 -07: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 25495ad0be fix(ui): focus scoped windows for notification clicks (#113951) 2026-07-25 19:00:50 -07:00
Peter Steinberger 33876991e7 fix(ui): stop false critical alerts for the selected session (#113932) 2026-07-25 18:12:05 -07:00
Peter Steinberger fb26903d6c feat: add flexible multi-sidebar chat layout (#113712)
* feat(ui): add persisted sidebar layout model

* feat(ui): render flexible chat sidebar columns

* test(ui): align board sidebar fixture type

* fix(ui): preserve sidebar panels across responsive layout

* fix(ui): satisfy sidebar CI ownership and performance

* test(ui): derive discussion helpers from panel config

* test(ui): mount session rail through its registry

* fix(ui): preserve sidebar state across projections

* style(ui): format sidebar state fixes

* fix(ui): satisfy sidebar lint constraints

* refactor(ui): break sidebar layout import cycle

* fix(ui): stabilize sidebar panel rendering

* fix(ui): keep the narrow sidebar grid off for an empty layout

The two-row narrow grid reserved a panel row even with no sidebar panel open, halving the primary surface height on every default mobile chat pane.

* fix(ui): lazy-load chat sidebar region

* style(ui): format rebased chat state page

* chore(ui): raise sidebar startup baseline

* fix(ui): preserve sidebar move and resize state

* chore(ui): align sidebar startup baseline

* chore(ui): refresh sidebar startup baseline

* test(ui): register discussion element in isolated test

* fix(ui): persist the dragged panel as the collapsed active panel

Drag moves activated the panel in its destination column but left the separate persisted collapsed-mode selection stale, so the narrow layout foregrounded the wrong panel after a move and the stale choice survived reload.

* fix(ui): preserve resolved canvas URL in detail panel
2026-07-25 17:45:29 -07:00
Peter Steinberger 52c11daed6 fix(control-ui): renew canvas capability so agent widgets keep rendering (#113702)
* fix(control-ui): renew canvas plugin surface capability so widgets keep loading

* fix(control-ui): scope canvas capability renewal to connections

* test(control-ui): cover rotated capability on a newly mounted widget

* fix(control-ui): bind canvas URLs to mounted frames

* fix(control-ui): keep reported widget heights across capability rotation

* fix(control-ui): keep canvas lease type private

* test(gateway): prove Canvas capability rotation over HTTP

* perf(control-ui): lazy-load canvas surface renewal

* chore(control-ui): raise startup budget baseline for canvas renewal lease

* fix(control-ui): satisfy promise-executor lint in gateway store test
2026-07-25 16:14:20 -07:00
Peter Steinberger 81d9d1a1f4 feat: announce critical session health beyond the rail and teach companion delegation (#113819)
* feat(agents): teach Control UI companion usage

* feat(gateway): announce critical observer health

* test(ui): cover critical observer notice flow

* fix(ui): wire critical notice strings to real i18n keys

* fix(ui): complete session row literal in notice test

* perf(ui): lazy-load critical observer notice off the startup chunk

* test(ui): capture post-navigation e2e artifact
2026-07-25 14:46:12 -07:00
Peter Steinberger e279076010 fix(ui): carapace follow-ups — embed font stacks, data-theme-resolved, undefined status tokens (#113724)
* feat(ui): publish carapace embed font stacks to MCP apps

Adopt the carapace embed contract's sandbox-safe font stacks: publish
--font-sans for the first time and switch --font-mono from the host's
JetBrains-led token to the embed mono stack. Both are static, system-
resolvable values byte-identical to carapace candidate/embed.css, since
the sandbox font-src policy silently drops brand faces.

* feat(ui): emit data-theme-resolved alongside theme attributes

Carapace CSS selects on [data-theme-resolved]; keep it in lockstep with
data-theme-mode at boot (index.html IIFE) and on every runtime theme
change (bootstrap publish path). Rename applyStartupPresentation to
applyThemePresentation: it runs on every theme change, not just startup.

* fix(ui): resolve undefined --success/--warning tokens and drop dead hex fallbacks

--success and --warning were never defined (real tokens: --ok/--warn),
so sites with literal fallbacks rendered off-palette one-off colors and
sites without them silently dropped declarations (invalid color-mix in
the chat sidebar warn banner). Map all uses to the semantic tokens
across board, chat sidebar/layout, layout, and components styles, and
strip the stale dead var() hex fallbacks in these global stylesheets.
Code-syntax palette hexes in the file view are documented as deliberate.
2026-07-25 09:32:56 -07:00
Peter Steinberger 29e02e84cd fix(ui): prevent dashboard startup flash (#113558) 2026-07-25 00:49:03 -07:00