71 Commits

Author SHA1 Message Date
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
Peter Steinberger 9e0780c5a0 fix(ui): styling sweep — compact number steppers, one accent for check controls, composite-page cleanups (#110845) 2026-07-18 18:34:19 +01:00
Peter Steinberger 8a66aa76dd feat(ui): session board grid engine and board view (#110644)
* feat(ui): add session board grid view

* fix(ui): use shared board controls

* fix(ui): keep board cell registration type-safe

* chore(ui): drop unused board cell class export
2026-07-18 09:40:41 -07:00
Peter Steinberger 88e5af7097 feat(ui): interleaved sidebar zone with custom session icons and drag ordering (#110682)
* feat(ui): custom session icons with agent-drawable SVG and nav-parity pinned rows

* wip: slice-2 interleaved sidebar zone (pre-review)

* fix(ui): trim icon exports, bypass protocol barrel in startup bundle, regen Swift protocol client

* fix(ui): preserve unknown-agent zone entries on writes, prune entries on any unpin

* fix(ui): reset keeps unloaded session slots; enforce SVG byte cap on canonical form

* fix(ui): archiving a pinned session retires its sidebar zone slot

* fix(ui): persist drag-pinned zone slot only after the pin patch lands

* fix(ui): recompute drop insertion against freshest zone order on pin ack

* fix(ui): consume self-drop events before the zone bailout

* docs(ui): note the non-sidebar unpin pruning contract on pruneSidebarSessionEntry

* refactor(ui): extract pure session-tree projection; drop unused zone type export
2026-07-18 17:13:09 +01:00
Peter Steinberger 74880cb56f feat(ui): manage MCP servers directly from Settings → MCP (#110654)
* feat(ui): manage MCP servers directly on the Settings MCP page

* refactor(ui): mcp config section owned by the MCP settings page only

* chore(ui): drop test-only McpServersCard export for knip
2026-07-18 12:54:05 +01:00
Peter Steinberger 6032dec3ba fix(ui): make mock sessions archive flow usable (#110556)
* fix(ui): complete mock sessions archive flow

* fix(ui): scope archive filtering to stateful fixtures
2026-07-18 09:27:01 +01:00
Peter Steinberger f93bfc240b fix(ui): render pinned sessions headerless like sidebar nav entries (#110476) 2026-07-18 08:20:52 +01:00
Peter Steinberger 75e4103c57 feat(ui): five-zone sidebar — agent identity card, threads/groups/coding, footer bar (#110259)
* feat(ui): five-zone sidebar with agent identity card, threads/groups/coding zones, and footer bar

* fix(ui): promote main-session children via the gateway row's literal key

* fix(ui): filter and sort promoted main-session threads; hide empty Coding count

* fix(ui): collapsed zones no longer consume the visible session page budget

* fix(ui): a11y — offline card label and catalog lists outside the Coding list container

* fix(ui): zone headers use pre-pagination counts so paged-out zones stay visible

* chore(ui): document catalog-adoption dedup invariant on promoted threads

* chore(ui): seed five-zone sidebar fixtures in the mock-dev harness

* fix(ui): resolve the canonical global main key for the identity card under global scope

* fix(ui): global scope resolves the global sentinel as canonical main even pre-hello

* fix(ui): drop dead channelDisplayLabel, avoid map-spread, type zone test helper
2026-07-18 02:39:17 +01:00
Peter Steinberger 2ecc6b6b6b fix(ui): show restart banner for unapplied config (#107577)
* fix(ui): derive config apply state from gateway

* test(ui): align applied config hash coverage

* test(ui): follow config autosave flow

* fix(ui): guard applied config refreshes

* fix(ui): reconcile patched config revisions

* fix(ui): prevent stale config apply polling

* chore: leave release notes to release flow

* refactor(config): split applied revision helpers

* style(config): format gateway methods

* fix(i18n): refresh Korean native glossary hash
2026-07-14 08:43:35 -07:00
Peter Steinberger d6fc3d34e2 improve(ui): auto-save config edits, flatten config pages, single restart affordance (#107458) 2026-07-14 05:31:41 -07:00
Peter Steinberger cf8b57e7d0 feat(skills): scan session history for workshop ideas (#106766)
* feat: scan past sessions for skill proposals

* feat(ui): add progressive skill history scans

* fix(ui): keep skill history scans synchronized

* refactor: split skill history scan ownership

* style: fix mock helper formatting

* style: format skill history scan

* build: refresh skill history schema baselines

* build: refresh plugin SDK baseline after rebase

* perf(ui): keep startup request budget bounded

* fix(skills): satisfy history scan integration gates

* fix(ui): bound control ui startup chunks

* build: refresh plugin SDK API baseline

* build(ui): refresh self-learning translation memory

* refactor(ui): split skill workshop state

* fix(ci): refresh skill workshop gates

* fix(ci): satisfy skill history lint

* build: refresh plugin SDK baseline after main rebase
2026-07-13 16:15:50 -07:00
Peter Steinberger 2d362a9b01 fix(ui): show mock task transcripts (#106774) 2026-07-13 14:39:47 -07:00
Peter Steinberger e3c5821d98 feat(ui): redesign Channels page with guided channel setup wizard (#106469)
* feat(ui): redesign Channels page with guided channel setup wizard

Adds wizard.start flow=channels gateway RPC (additive protocol change) that
drives the shared channel-setup wizard (openclaw channels add) over the
session step protocol. Control UI Channels page becomes a card hub with
plugin-art covers, guided per-channel setup modal (WhatsApp QR pairing via
web.login.*, BotFather/Slack/Discord helper links), and a detail overlay
hosting the full schema config form.

* test(ui): cover channel wizard controller; refresh channels view test props

* chore(mock): use non-token-shaped wizard placeholder

* test(gateway): scanner-safe auth local in channels wizard test

* fix(ui): cancel gateway wizard session on channels page disconnect

* fix(ui): adopt browse-all channel pick and guard dirty config before setup

* fix(ui): cancel gateway session created by a stale wizard.start

* fix(ui): adopt multiselect channel picks; drop redundant String()

* fix(ui): track all wizard-adopted channels so WhatsApp QR runs regardless of pick order

* feat(gateway): report configured channels on terminal channel-wizard result

Replaces the Control UI's channel-adoption heuristic with the authoritative
outcome: the channels flow reports its actual selection after config commit,
the wizard session surfaces it as an additive channels field on the terminal
wizard.next result, and the UI keys WhatsApp QR linking off that.

* refactor(ui): align channels hub with the unified settings design language

Hub becomes settings-language rows (44px art tiles, status dots, uppercase
section headings, hairline groups) instead of a card gallery; the detail
overlay hosts the migrated per-channel settings sections with Run setup in
the header. Wizard dialog and tile/cover styles move to spacing tokens.

* chore(i18n): translate channels hub/setup strings; refresh raw-copy baseline

* refactor: satisfy LOC ratchet and dead-export gates

Split mock-dev channel/plugin fixtures into their own modules, move wizard
runner types/defaults to server-methods/wizard.ts, extract the channels page
wizard host and nostr profile HTTP ops, and unexport internal-only types
(incl. the unused config-form SECTION_META barrel re-export).

* chore(i18n): retranslate channels strings on rebased locale bundles

* fix(test): drop redundant String() in channels wizard e2e

* fix: address channel-wizard review findings

- lock wizard cancellation before durable installs/config writes
- report configured channel accounts on the terminal wizard result and
  start WhatsApp QR pairing for that account (web.login accountId)
- forward request options through the browser gateway client so wizard
  RPC timeouts apply
- render skipped setup as a no-change completion
- keep detail/advanced config reachable for unconfigured channels
- surface the dirty-config warning inside the detail overlay
- adopt the picked channel for wizard title/links in browse-all flows

* fix(ui): local wizard RPC timeout; translate no-change completion strings
2026-07-13 11:49:42 -07:00
Peter Steinberger b9ab918354 feat(ui): surface still-running background tasks after the chat turn settles (#106115)
Control UI chat now keeps still-running background tasks visible after the agent turn settles: a status row above the composer shows the claw glyph parked nose-down (static, opacity breath only), a live elapsed time with tabular digits so the row never shifts, and a "1 running task"/"N running tasks" link that opens the background-tasks rail. The row hides while the agent is working, while disconnected, and once the last task finishes. Reuses the pane's existing tasks.list snapshot and live task events — no new polling or RPC. Includes a mock-dev-harness running-task fixture and generated locale translations for the two new strings.

Closes #106107

Evidence: focused suites green on Blacksmith Testbox (chat-background-tasks 16 tests, chat-view 185 tests); live mock-gateway verification with screenshots on the PR; autoreview (gpt-5.6-sol, xhigh) clean after fixing its two findings (aria-hidden ticking timer, disconnected suppression).
2026-07-13 01:25:56 -07:00
Peter Steinberger 5b7b2d0fe0 feat(ui): collapse completed turn work behind a "Worked for X" rollup (#105012)
* feat(ui): collapse completed turn work behind a worked-for rollup

* test(ui): add a completed work turn to the mock chat history

* fix(ui): keep search matches visible instead of folding them into the work rollup

* fix(ui): keep attachment-only final replies outside the work rollup

* chore(ui): translate workRun locale keys and cover renderWorkGroupSummary mock

* fix(ui): satisfy strict index access in the work rollup pass
2026-07-12 19:01:45 +01:00
Peter Steinberger e580275464 feat(tooling): enforce noUncheckedIndexedAccess in the scripts lane (NUIA phase 5) (#105180)
* feat(tooling): enforce noUncheckedIndexedAccess in the scripts lane

Burns down all 153 scripts-lane errors (bench aggregation, release
checks, i18n inventories, argv indexing) and flips the flag in
tsconfig.scripts.json. Direct-Node-executed release harness scripts use
local narrowing instead of workspace imports, which do not resolve
under plain node execution. Benchmark measured loops untouched.

* fix(scripts): import expect helpers via relative package sources

tsconfig path aliases resolve from cwd under tsx, so release wrapper
scripts running against old release target cwds could not resolve
@openclaw/normalization-core (not a linked root dependency). Relative
package-source imports match the established pattern on the adjacent
lines and are cwd-independent; old-target planning verified directly.
2026-07-12 10:17:00 +01:00
Peter Steinberger dd5928711a feat(ui): fold Skills and Skill Workshop into a Plugins hub (#104834)
* feat(ui): fold Skills and Skill Workshop into a Plugins hub

One sidebar entry (Plugins) now covers plugins, skills, and skill-workshop
routes via a shared hub tab strip (Installed / Discover / Skills / Workshop).
Routes and URLs are unchanged; /settings/plugins gains ?tab= deep links and
the sidebar highlights Plugins for all hub routes.

Also latches Skill Workshop proposal loading so updated() no longer re-kicks
loads while one is pending or after one fails - the early-return finally
used to spin the page at 100% CPU whenever skills.proposals.list stalled.

* feat(mock): plugin catalog and skill-workshop fixtures for the mock harness

* docs(web): describe the Plugins hub tabs in the Control UI guide

* test(ui): backfill initialTab in plugins route-data fixtures

* fix(ui): review fixes for the plugins hub

- plugins route declares loaderDeps on the ?tab= param so query-only
  navigation and back/forward re-run the loader instead of reusing the
  cached match with the previous tab
- catalog tab clicks navigate so the URL and history stay in sync with
  the documented ?tab=discover deep link (local switch stays instant)
- skill-workshop error banner gains a Try again button so a transient
  proposals-list failure is recoverable without remounting the route

* fix(ui): restore the Installed tab on bare plugins URLs in history navigation

* fix(ui): manual-activation hub tablist with cross-route focus hand-off

Arrow keys only move focus now; activation stays on click/Enter so arrowing
can never unmount the strip under the user's focus. Keyboard activation of a
cross-route tab hands focus to the destination strip's active tab, and the
hub-route set uses a Set per lint.

* fix(ui): defer hub-tab focus reclaim until the strip is connected

* fix(ui): skip focus recovery for same-tab hub activation

* docs(css): note the hub-panel flex ownership for the workshop board

* fix(ui): adapt hub test to retired Overview route

* chore(i18n): sync locale bundles for the plugins hub keys

* docs(map): regenerate for the plugins hub section
2026-07-11 22:03:38 -07:00