A search-first model picker for dsh. Companion to deepseek-peak.
Replaces the composer model seat (conversation.input.model) with a search-enabled variant. The seat shows the current model name; click it to open a popover with a search input at the top of the catalog. Filter as you type, ↑/↓ to move, Enter to pick, Esc to close. The selection lands through the same select verb the upstream model seat uses, so the host-reported current model is the single fact source.
./install.sh /path/to/your/dshOr, on Windows, the PowerShell port does the same:
powershell -NoProfile -ExecutionPolicy Bypass -File .\install-pick-port.ps1Then start dsh:
cd /path/to/your/dsh
pnpm dsh webThe "Pick model" seat is the composer model selector itself. Click it → the popover opens above with the search input on top of the group-organized model list.
./uninstall.sh /path/to/your/dshThe upstream /model popup is a flat list with no search. Once a deployment has more than a handful of models — and a typical model catalog has DeepSeek V4 Flash, V4 Pro, plus anything else the user has wired in — finding the right one becomes a scroll. A search-first picker (Cmd-K-style) is the standard remedy.
This plugin reuses dsh's existing ModelDirectoryResolver; it doesn't fork state with the upstream picker. The seat shows the same current because the host is the single fact source, and a pick made via the /model command-line popup (which is unaffected — it lives in a different surface) is what the seat shows next.
conversation.input.model is a kind: 'single' slot — only one occupant. The last registration wins. The pick row in cordis.patch.yml is placed after ui-model-selection, so the pick seat shadows the upstream seat. The upstream's /model command-line popup is a separate surface and is unaffected.
If you want to keep the upstream's flat list instead, move the ui-pick row in cordis.patch.yml to before ui-model-selection. The upstream seat will then shadow the pick seat.
deepseek_pick/
├── package.json # the standalone project (no host here)
├── install.sh # Linux/Mac install: cp -R, then JSON patches
├── install-pick-port.ps1 # Windows PowerShell port
├── uninstall.sh # reverses the install
└── harness-plugin/ # the dsh plugin source
├── package.json # @deepseek-ai/dsh-client-ui-pick
├── tsconfig.json
├── tsdown.config.ts
└── src/
├── index.ts # host-side no-op apply() + re-exports
├── invariant.ts # host/client identity check
└── client/
├── index.ts # apply(): slots.inject('conversation.input.model', ...)
├── PickButton.tsx # the model seat: current name + chevron
├── Picker.tsx # the popover: search input + group-organized list
├── Picker.module.css
├── locales.ts # en + zh dictionaries
└── slots.ts # PickModelInjected (mirror of upstream ModelSelectInjected)