Files
deepseek-harness/packages/client/ui-slots
Tianyi Cui a7a5be1703 docs(notes): archive low-future-value Agent Notes
Run the dsh-archive-agent-notes audit over every active Agent Note on
current master, judging each record by whether its rationale still guides
work rather than by size or age.

- Archive 453 implemented bilingual triplets (417,882 English words):
  completed UI chrome, narrow adapters, closed bug fixes, implementation
  walkthroughs whose package READMEs, docs pages, generators, or successor
  notes now carry the useful behavior, and 51 records fully superseded by
  a later active note. Keep 201 implemented notes whose ownership rules,
  negative guarantees, durable or wire semantics, security rules,
  reintroduction conditions, or still-tempting rejected alternatives
  remain useful.
- Reject 7 proposals whose premise is gone or whose work shipped in
  amended form under other records; delete 2 rejected notes that no
  longer prevent a plausible mistake.
- Retarget every remaining inbound link to the archived path, and repair
  active prose that named an archived record as the owner of a live fact:
  parenthetical citations drop, ownership sentences redirect to the
  README, docs page, or active note that states the fact, and history
  citations say so. Chinese files link the English archived path because
  the pairing gate treats the frozen tree as outside the bilingual corpus.
- Seal 1,359 new frozen artifacts; existing seals are unchanged and
  outbound links from archived notes are neither inspected nor repaired.
- Regenerate docs/config-catalog.md after the hook-bridge comment edits
  shifted two source line numbers.
2026-09-05 14:37:32 +08:00
..
2026-09-04 15:38:55 +08:00

description, kind
description kind
Slot registry pure core for the dsh web client: SlotMap declaration merging, the single register composition API, four-share props types, store seats, and the renderer install contract. package-library

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

English | 中文

Summary

dsh-client-ui-slots is the pure core of the web client's slot system: the type-level contract every UI feature composes through. One register({ name, children?, store?, inject?, ...kind }, Component) call contributes a component into a declared slot and, in the same breath, declares child slots, a store seat, and the registrant's business face. The component is checked at the call site against ComposedProps — the intersection of four shares, each derived from its single source of truth — so a wrong composition fails to compile. Chain-kind slots invert keyed routing: entries self-nominate through a pure selector instead of the dispatch site picking an entryKey. The package is React-free and Cordis-free at runtime (React types only); ui-renderer owns the engine implementation and React bindings.

Table of Contents


Use this package

Compose UI through this package whenever you write a client plugin: register a component into a slot your parent declared, or declare child slots your component renders. The four kinds cover the composition shapes — single (one occupant), list (ordered entries), keyed (dispatch by a key), and chain (entries elect themselves).

The four props shares

Every registered component receives props composed from four shares: the runtime share (owner from the parent's renderSlot call site, plus the session standard kit and global seat), the child-render share (renderSlot statically narrowed to the declared children keys), the store share (the declared handle's selector hook and draft-stripped actions), and the business share (inferred from the inject factory's return). Components reference ComposedProps; they never re-type a share locally.

Store seats

A register call may declare a store seat with store: defineStore(...): init infers the state schema and actions is the complete draft-transform write set. Components read through the selector hook and write through the baked callbacks; the engine implementation of defineStore lives in the runtime package and satisfies the DefineStore contract exported here.

Declaration discipline

Declaring a slot is claiming it: the registering entry becomes the only entry allowed to render that key, and registering into an undeclared slot, declaring an already-declared child, mounting one shared handle under two scopes, or registering a chain without select throws at load. An entry's disposer collapses its declared child slots recursively — ledger rows, contributions, and store mounts die on one lifecycle axis.


Understand the implementation

Implementation internals — click to expand

The design is one table: declaration = render authorization = runtime spec. SlotMap is declared empty here and merged by consumers via declare module augmentation, exactly like the standard-kit interfaces (SessionStandardProps, GlobalStandardProps), which the runtime package merges with real members.

Registration and routing

SlotCore seeds the a-priori 'root' slot at construction and enforces load-time validation. ChainSelect selectors run in ascending priority order (ties in registration order); the first non-null return elects its entry and becomes the component's matched prop, and all-null falls to the owner's renderSlotChain fallback (ChainRenderOpts). Each key carries a declaration epoch that advances only on declaration and collapse; ui-renderer uses it for ctx.slots.inject, independently from ordinary entry versions.

The renderer contract

renderer.ts carries the installation contract (SlotRenderer, SlotRendererHost) plus StaleAuthorizationError/SlotOwnershipError; ui-renderer owns both the implementation and its plugin-lifecycle installation. Engine products and the renderer host contract carry bare snapshot sources (getSnapshot/subscribe), never React hooks — hook binding belongs to the render machinery.


Further Exploration

These pages cover the engine, the renderer, and the composition model.


Model Experience

None, as the package is a browser-side UI plugin layer that registers nothing model-facing.

KV Cache effect

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

Known Limitations and Deferred Work

These limits define the registry's scaling behavior and accepted type noise; they are current package constraints.

  • isLive scans all records linearly — fine at UI-plugin registration counts (tens); revisit with an entry→record backref if ledgers ever grow hot.
  • The __renders phantom anchor is visible on PropsRenderSlots — the same accepted noise as the type-chain design's __accepts: generic method signatures compare loosely across key unions, so the contravariant marker is what enforces "component key set ⊆ children declaration".

Dev Note

Working context for maintainers — click to expand

None.

Runtime invariant: No companion is published. A zero-dependency pure registry core — it emits no cordis events itself (the ui-renderer SlotRegistry owns the event bridge and its invariants); define/register/dispose sequencing is asserted directly by this package's behavior specs.