Files
deepseek-harness/packages/client/ui-sidebar
creatixchu 10ce8d8a45 fix(web): decide the sidebar's pointer leave by geometry, and tighten the gate
Review findings from the first round:

- ui-settings renders its full-viewport panel as a fixed-position DESCENDANT
  of the sidebar column, so `pointerleave` never fires when the pointer moves
  onto it and the bars stayed drawn after it closed. Leaving is now decided
  against the column's box from a document-level pointermove that exists only
  while the bars are drawn; the element's own leave stays for the pointer that
  leaves the window.
- The rebind gate judges the rule rather than each declaration, so a pair that
  mixes `transparent` with an l2 hover no longer passes, and the elevation
  half compares whole values instead of token shape.
- Hiding no longer exempts a sheet from the elevated-surface rebind check.
- The e2e polls the reveal before reading a colour for the golden, and pins
  that a pointerless scroll draws no thumb.
2026-08-04 15:42:39 +08:00
..

@deepseek-ai/dsh-client-ui-sidebar

English | 中文

Sidebar plugin: real Host Workspaces in stable Host order, each containing its sessionIds in Workspace order with parentId nesting; Sessions outside every Workspace appear in a trailing Ungrouped section. Search, state dots, and collapse into the layout-owned 56px rail are presentation-local. Contract: the slot system standard.

New Session starts the runtime's page-local frontend Session Intent; a real Workspace's "+" starts one targeted to that Workspace. The Workspace header "+" opens ui-workspace's shared picker, whose selection also targets a frontend Session. A Workspace Intent does not appear in the sidebar.

SidebarRootComponentProps composes the layout owner share, the global useSessions and useWorkspaces hooks, the declared sidebar.workspace and sidebar.settings child slots, and injected startSession, open, and sidebar-toggle callbacks. There is no plugin store: deriveGroups consumes object-layer snapshots and component-local expansion/search state.

Scrollbars in the column are a pointer affordance: the shell rebinds ui-theme's scrollbar indirection to transparent whenever the pointer is outside it, and keeps the thumb drawn for 2s after the pointer leaves, so a list nobody is pointing at carries no bar. The reservation that keeps rows from moving belongs to the scrolling region (ui-workspace), so revealing a thumb never reflows.

The foot is the sidebar.settings seat: the sidebar renders only the bottom-pinned layout slot and shares its column state (wide); ui-settings registers the trigger row and settings panel there.

The /client export surface is the plugin body (apply/inject) plus the contract types only — SidebarRoot, the row components, and the tree derivation are internal (the slot registration closes over them; tests import src paths directly).

Model Experience

None, as the sidebar renders the browser session list; nothing here reaches a model request.

KV Cache effect

None; this package neither assembles nor sends a provider request.

Known Limitations and Deferred Work

  • Session state-dot rendering is owned by ui-workspace — done/error notification sources remain deferred.
  • Group-by menu ships by-workspace only — Update/Status grouping strategies are drawn without specs and deferred.
  • "New task completed" unread marking is local viewing state — completion-time > last-seen never reaches the host.