Back to home@pangzi-club

dsh-client-ui-selection-add

No description

Stars
0
Language
TypeScript
Created
Aug 24, 2026
Updated
Aug 24, 2026
GitHub repo

Introduction

dsh-client-ui-selection-add

English | 中文

Source: pangzi-club/dsh-client-ui-selection-add

Web selection-add feature plugin: its browser half contributes a floating Add to conversation button into the conversation-owned conversation.input.dock slot. While a session's composer is mounted the plugin listens for text selection; a non-empty, non-editable selection floats a small button just above its bounding box, and clicking the button fills the composer draft (inputActions.setDraft) without sending — the user reviews and hits Enter (or the send button) themselves. Its host half is empty on purpose: capturing a selection and prefilling the draft is pure browser-surface presentation, so there is nothing for the Host to own.

The component is mounted in a session-scope list slot, so the framework delivers the session standard kit (useSession, sessionId, useProjection, useInput, inputActions) plus the session/input owner share and the selection locale seat; the component only reaches for inputActions and t. Because the button is a body-level portal, the dock entry renders nothing itself — the composer layout is untouched.

Two behaviors worth calling out:

  • Prefill, not auto-send. The click is setDraft(text); submit() is deliberately not called, so the user can edit the quoted text before it goes to the model. (Sending on click is a one-line change in SelectionAddButton.)
  • Editable-field guard. Selections inside an input, textarea, or contenteditable never show the button — selecting inside the composer is editing the draft, not quoting the conversation, and the button would fight the caret.

The button copy is bilingual under the selection namespace of dsh-client-locale. The anchor capture lives in a framework-free selection.ts module (selectionAnchorOf / isEditableField), unit-tested on its own.

Model Experience

None. Everything here is a browser interaction: the model never sees a tool, a session event, or a schema. The plugin is a pure presentation surface over the input machine's public inputActions face.

KV Cache effect

No invalidation. The plugin reads no session data and publishes no session events, so the conversation log, projections, and KV caches are untouched.

Known Limitations and Deferred Work

  • Not scoped to the transcript body. The selection listener is document-wide; the only guard today is the editable-field check. Selecting in the sidebar or settings shows the button because the plugin cannot identify the transcript scroll container without changing ui-conversation (the no-core-change choice above). Scoping it requires either a proper conversation.selection.* slot (see below) or a data-* hook the conversation skeleton already owns.
  • Prefill only. The user must confirm before send; there is no "send now" affordance on the floating button.
  • Multi-line selections anchor above the bounding box's top (the first line); a selection that starts near the viewport top may clip the button.
  • View-chat only, by construction. The button only mounts while a session composer is mounted, so it does not appear in the no-session hero. It does not distinguish which view tab is active.

Extension point (the "proper slot") upgrade

The current path rides the existing conversation.input.dock, so it requires zero changes to ui-conversation. To make the capture a first-class extension point instead, add a session-scope slot to ui-conversation (packages/client/ui-conversation/src/client/apply.ts children plus the contract/slots.ts SlotMap merge), e.g. conversation.selection.action { kind: 'list', scope: 'session' }, and register this plugin's entry there.

Build and publish independently (community plugin)

The package is a buildable, independently publishable DSH client plugin. It does not need the deepseek-harness monorepo to compile: package.json, tsconfig.json, and tsdown.config.ts are all standalone, and the @deepseek-ai/* imports are import type only, so they resolve from node_modules at their published versions.

Build

pnpm install
pnpm bundle        # tsc (emits lib/types/**/*.d.ts) + tsdown (emits lib/*.js)
pnpm watch         # tsdown --watch

Output:

  • lib/index.js — host half (empty apply; the browser half does all the work)
  • lib/invariant.js — invariant companion
  • lib/client.js — the browser module-table bundle (window.__ModuleLoader__.load({ id, factory }))
  • lib/types/**/*.d.ts — TypeScript declarations

Publish

pnpm bundle first (or rely on prepack, which runs it automatically), then:

npm publish            # or pnpm publish

The published surface is the files list: lib/*.js (+ maps) and lib/types/**/*.d.ts, plus cordis.patch.yml.

Install into DSH (community plugin)

This package declares the dsh.bundle manifest, so it installs via the same channel as any community plugin (installing it from npm):

npm install dsh-client-ui-selection-add
dsh plugin --profile web add dsh-client-ui-selection-add

or, for a local build:

  1. Symlink/junction this directory into $DSH_HOME/profiles/node_modules/dsh-client-ui-selection-add.
  2. Append the host row to $DSH_HOME/profiles/web/cordis.patch.yml:
    - insert:
        - id: ui-selection-add
          name: dsh-client-ui-selection-add
    
    (or just dsh plugin add writes it for you via dsh.bundle.patchcordis.patch.yml).

The client half registers into the framework-owned conversation.input.dock slot and pulls the locale service. Both are provided by the stock dsh web build (@deepseek-ai/dsh-client-ui-slots, @deepseek-ai/dsh-client-locale, @deepseek-ai/dsh-client-ui-conversation), so a stock dsh web build resolves the runtime. Because these framework packages are not all baseline module-table rows (they're separate dsh.client graph rows), a bare community install only works against a DSH Web build that already activates them — which is the case for upstream dsh web.

Cross-reference: deepseek-harness monorepo

This repository is the standalone home of the package. The same sources are also wired into the deepseek-harness monorepo as @deepseek-ai/dsh-client-ui-selection-add at packages/client/ui-selection-add; there the tsdown preset and the three registration surfaces (tsconfig.client.json reference, packages/bundle/web-app/cordis.patch.yml dsh.client roster row, packages/bundle/web-app/package.json dependency) come from the monorepo itself. This checkout builds and publishes from the self-contained configs above instead.