design-platform.css declared four --dsw-alias-scrollbar-* tokens in both palettes that no rule read, so every scrolling region rendered the user agent's own scrollbar and the dark theme showed a light native bar against dark surfaces. The symptom that surfaced the gap was in the sidebar: the workspace browser's session list is its only scrolling region, and each row's trailing content (the relative timestamp, and the hover action buttons that replace it) is `flex: none` flush against the row's 8px right padding, so an overlaid scrollbar painted on top of the timestamp. ui-theme/styles/scrollbar.css becomes the sole consumer of the four tokens, imported by the web shell's base.css after design-platform.css because it reads that sheet's tokens. The rules sit on `body`, not `html`: the alias tokens are declared on `body`, custom properties inherit only downward, and from `html` they resolve to the guaranteed-invalid value with scrollbar-color computing to `auto`. scrollbar-width and scrollbar-color are declared on `body, body *` rather than inherited, because inheritance would carry the color already substituted at `body` and an elevated surface could not retint its own thumb; scrollbar-width does not inherit at all. Both the standard properties and the ::-webkit-scrollbar pseudo-elements read one indirection pair bound to the l1 tokens, so an elevated surface rebinds that pair to the l2 tokens once and retints both renderings. The command popup, slash menu, model-select panel, and settings panel do so, which gives the l2 tokens their first consumers. WorkspaceBrowser's `.list` declares scrollbar-gutter: stable, keeping the bar beside the rows. `stable` rather than `auto` so the reservation holds when the list is short enough not to scroll: expanding a workspace group would otherwise shift every row sideways at the moment it starts scrolling.
@deepseek-ai/dsh-client-ui-workspace
English | 中文
Shared Workspace picker plugin. WorkspaceBrowser is registered into the sidebar's sidebar.workspaces slot and WorkspacePicker into the page-local Session Intent hero's conversation.hero.workspace slot, so both surfaces use the same menu and creation flow.
The picker lists real Host Workspace entities through the global useWorkspaces hook. Selecting a Workspace invokes the slot owner's onPick callback to retarget the frontend Session object. The flat Open local folder... action delegates to the Host's native single-directory picker, adopts a returned path through the object layer, and selects the committed Workspace only after its list projection has refreshed; cancellation is silent, and errors remain retryable. Create a new workspace retains the name dialog and disables names already present in that list, while the Host remains authoritative for concurrent or non-UI callers. The runtime Session and Workspace services own materialization. The Workspace row's Delete action opens a confirmation that states the retention boundary, blocks duplicate submission, and keeps failures open; success removes the group while its Sessions remain under Ungrouped.
Both target slots are declared by other plugins, so apply registers through declaration-aware deferral and re-registers after a declaring slot is restored.
Model Experience
None, as the picker is browser chrome; nothing here reaches a model request.
KV Cache effect
None; this package neither assembles nor sends a provider request.
Known Limitations and Deferred Work
- No Session deletion control — the existing Session menu row remains visual-only; Workspace registration deletion does not delete Sessions.
- Native folder selection depends on the local Host carrier — fixture-only or remote browser deployments cannot open a local operating-system dialog; platform failures are shown in a retryable modal.