dsh-fetch-models-search
DSH plugin: adds a search box to the Fetch available models candidate dialog in DSH settings (browser-side DOM enhancement). DSH 插件:为「获取可用模型」候选弹窗增加搜索过滤。
- Stars
- 0
- Language
- JavaScript
- Created
- Aug 26, 2026
- Updated
- Aug 26, 2026
Introduction
dsh-fetch-models-search
Add a search box to the Fetch available models dialog in DSH settings → Models — filter the candidate model list as you type.
A pure browser-side DSH plugin. It injects a search input above the candidate list opened by Fetch available models and filters rows in real time (case-insensitive substring match on the model id). It does not modify or patch any component code — it is a self-contained DOM enhancement that degrades to a no-op when the dialog is not present.
Features
- 🔍 Search box injected at the top of the candidate model picker; type to filter instantly.
- 🧱 No component modifications — built entirely on stable DOM structure, no CSS-hash class selectors.
- ♻️ Survives React re-renders: a
MutationObserver(frame-coalesced viarequestAnimationFrame) re-applies the current filter whenever the candidate list is rebuilt. - ✓ Filtering never touches checkbox selection or the Select all / Deselect all semantics.
- 🧹 Fully reversible: only
displaytoggles and one injected style element; uninstall restores the page exactly. - 🌐 Localized: search placeholder and "no matches" hint follow the page language (
zh⇒ Chinese). - 🪶 Zero runtime dependencies: the bundle does not
importany@deepseek-aimodule at runtime and ships its complete__ModuleLoader__.loadclosure factory wrapper.
Installation
Install from GitHub into the web profile:
dsh plugin --profile web add github:masknull/dsh-fetch-models-search
Or, from a local checkout:
dsh plugin --profile web add link:D:\.dsh\plugins\dsh-fetch-models-search
# or from the package directory itself:
dsh plugin --profile web add .
Restart DSH Desktop / the dsh service after installing. The client-module graph (
window.__DSH_BOOT__) is composed at startup; a page refresh alone will not pick up a newly added plugin bundle.
Usage
- Open Settings → Models.
- Expand a pi-ai provider card and click Fetch available models.
- The picker opens with a search box above the candidate list. Type part of a model id to narrow the list; clear it to show all candidates again.
- Selection behaviour (checkboxes, Select all / Deselect all, Add selected) is unchanged.
How it works
- Targeting: the picker is a
ui-primitivesModalrendered viacreatePortalintodocument.body—role="dialog"+aria-modal="true". Its unique structural fingerprint is a<ul>whose<li>children containinput[type=checkbox](other dialogs, e.g. the delete-confirmation dialog, have no such list). No CSS-module hash class names are used, so the anchor is immune to theme/language changes. - Injection: a search
<input type="search">is inserted immediately before the candidate<ul>; a<style>element with--dsw-alias-*-token styling is injected once into<head>. - Filtering: rows keep their DOM nodes; non-matching ones get
display: none. A "no matching models" hint appears when the query yields nothing and disappears when cleared. - Lifecycle:
apply(ctx)registers the observer and hands a cleanup back throughctx.effect; the plugin unload restores everything (observer disconnected, style removed).
Uninstall
dsh plugin --profile web remove dsh-fetch-models-search
Package layout
| Path | Purpose |
|---|---|
cordis.patch.yml | bundle patch — inserts the fetch-models-search loader row |
lib/index.js | host half — empty apply (the row must exist host-side; the browser half is discovered via the dsh.client declaration) |
lib/client.js | browser half — search-box injection + filtering |
scripts/verify.mjs | jsdom end-to-end verification (18 assertions) |
Development & verification
node scripts/verify.mjs
The script loads lib/client.js through a simulated window.__ModuleLoader__, builds a dialog DOM isomorphic to the real picker, and asserts: correct dialog targeting (no false positives on other dialogs), injection, filtering, checkbox isolation, filter persistence across re-renders, no-match hint, re-open re-injection, and lifecycle cleanup.
Limitations
- Applies only to the Fetch available models picker; manually edited model rows are not involved.
- Matching is a case-insensitive substring match on the candidate id text only (no fuzzy / regex).
- Select all / Deselect all still targets all candidates (original behaviour unchanged by the current filter).