`SettingsRoot` and the `sidebar.settings` occupancy moved to ui-settings-general,
but both READMEs still read as if ui-settings were the shell. ui-settings now
documents what it actually is — the `ctx.settingsScope` transport plus the slot
type declarations, with the bind ownership, refresh triggers, write revision
handling, and decode refusal a preference row must know — and records the
loopback-only and single-field write gaps in place of two limitations that no
longer exist. ui-settings-general documents the shell it now renders. The stale
module JSDoc on both halves follows.
The settings shell painted the onboarding overlay (opaque stage, mask,
#root inert) the moment a step was registered and not locally completed,
while every step still had to load its private join before deciding
whether to show — rendering null could not suppress the shell-owned
chrome. Every reload on the hero therefore flashed a full-screen opaque
layer (white in the light palette) for one settings/credential RPC
round-trip after the session list turned ready.
The chrome now belongs to the step: a new zero-cordis OnboardingSurface
primitive (ui-primitives) renders the body-portaled overlay/mask/stage
verbatim from the former SettingsRoot stylesheet and holds #root inert
for exactly its own lifetime. WelcomeNotice and DeepSeekOnboardingDialog
wrap only their visible branch in it, so their existing null branches
paint and block nothing by construction. SettingsRoot keeps the
coordinator unchanged but renders the elected step bare, and the
settings.onboarding contract now names the surface wrap as the
registrant's obligation.
The onboarding e2e gains a held-join reload scenario pinning that a
configured world never mounts the takeover chrome or inerts the app.
The shell is now a pure composition face: no dictionaries, no locale
dependency, and three new chrome content seats (settings.trigger /
settings.header / settings.close) whose slot content also carries the
accessible names (trigger text, dialog aria-labelledby, visually hidden
close label). ui-settings-general returns as the owner of copy that
belongs to no single feature: chrome content, the General section with
its item slot, and the settings dictionaries. Slot types split homes —
trigger/header/close/section live in the shell contract; the
settings.general.item entry moves to the locale package (the common
dependency of every item registrant), with ui-theme consuming it
through a re-export seam; the verbatim duplicate merges are gone and
the dependency graph is a clean DAG.
Add the browser Settings surface as slot-composed plugins over new
preference services:
- Rename dsh-client-i18n to dsh-client-locale (locale is the domain
name); LocaleService adds getLocale()/setLocale(id), immutable
snapshots, a locale/change event, and dsh.locale persistence.
- ThemeService owns the light/dark/system preference (default system),
resolves system via prefers-color-scheme, publishes theme/change
snapshots, persists dsh.theme, and no longer touches the DOM;
ui-layout's ThemePresenter applies resolved snapshots
(body[data-ds-dark-theme] + alias tokens) and cleans up on dispose.
- ui-sidebar drops the phase-1 settings dropdown/modal; the foot renders
the new sidebar.settings slot with the column state.
- New ui-settings shell occupies sidebar.settings: foot trigger row and
the centered 1080x700 panel (figma 501:29947) with 24% mask, close
button / mask click / Escape all closing, and a 188px nav projected
from the settings.section list slot it declares. Nav labels are
registrant-localized; sections re-register on locale change, so the
ledger version is the shell's only subscription.
- ui-settings-general registers the General section: Permission and
Tool Call skeletons, live Language (locale menu) and Appearance
(Light/Dark/System cubes following the persisted preference); its
slot store mirrors both service snapshots via apply-side listeners.
- ui-settings-models registers the Models nav entry with an empty
content column.
- Portaled menus pin z-index above modal overlays (a menu anchored
inside the settings dialog rendered underneath it and was
unclickable).
- theme/data/list-pen icons in ui-primitives; settings copy ships as
zh/en dictionaries; fixture manifests gain the settings rows.