Skip to content
dsh.fish
Bundle

dsh-models-filter

Filter input for the composer model menu: case-insensitive list filtering with combobox keyboard navigation, rendered with the shipped menu design

Source
odelbos
License
MIT
Updated
Updated 6 days ago

Readme

# dsh-models-filter

A **DeepSeek Harness profile bundle** that adds a **filter input at the top of the
model-list pane** of the composer model menu. The root Model/Effort pane and
every other part of the menu stay exactly as shipped.

> [!CAUTION]
> This plugin has been **fully vibe-coded** with **GLM-5.3-FLASH** (Ox Alpha).  
> It was a simple exercise to try out the LLM during its free test phase.  
> _(Everything came straight from the LLM — code, comments, readme, etc.)_  
> I don't have any experience writing DSH plugins, so I can't vouch for the code quality.

> [!WARNING]
> I'm not a big fan of how the CSS classes are used inside the plugin, especially the const `C = {}` map, because in future versions of DSH the class hash prefix may change and this will break the plugin.  
> So this plugin is actually dependent on DSH's 0.1.1-rc.2 version.

> [!NOTE]
> [Post on X](https://x.com/odelbos/status/2093653458725347339) (with a short video showing the plugin in action)

## Install

From a local checkout:

```sh
dsh plugin --profile web add ./dsh-models-filter
```

Or straight from GitHub (any pnpm-compatible spec works):

```sh
dsh plugin --profile web add gh:<user>/dsh-models-filter
# or:
dsh plugin --profile web add git+https://github.com/<user>/dsh-models-filter.git
```

Then restart the profile (`dsh web`) so the new bundle layer composes in.
`lib/` artifacts are committed, so installs never need a build step and no
pnpm `allowBuilds` entry.

Uninstall with `dsh plugin --profile web remove dsh-models-filter`, or disable
just this row without removing the package by adding to the profile's own
`cordis.patch.yml`:

```yaml
- id: models-filter
  disabled: true
```

## What you get

- Opening the menu shows the unchanged Model / Effort cells — no filter there.
- Entering **Model** shows the list pane with the filter row on top,
  autofocused; typing filters case-insensitively by model name, id,
  description, or provider name/id; emptied groups drop out; `×` or `Esc`
  clears and restores the full list in place.
- **Combobox keyboard navigation:** `ArrowDown`/`ArrowUp` move a highlight
  across the visible rows (wrapping at the ends) while focus stays in the
  filter input — the highlight rides `aria-activedescendant`. `Enter` selects
  the highlighted row; `Escape` cascades clear query → back a pane → close.
  Typing resets the highlight to the first visible row.
- **Two-tier emphasis:** the pre-selected row carries a stronger layered fill
  so it reads clearly in both themes; mouse hover keeps the lighter shipped
  hover fill and never moves the pre-selection.
- **Deterministic scrolling:** wrapping to the first row snaps to top;
  otherwise the pre-selected row is revealed minimally, always fully below its
  sticky group title; already-visible rows cause no scroll.
- Selections flow through the shipped shared per-session `ModelDirectory`
  (`ctx.modelDirectories`), so `/model`, the composer trigger, selection state,
  and the composer's model-unavailable block stay exactly in sync.

## How it respects the existing design

- The menu renders with the **shipped stylesheet's own class names**
  (`_7KE1Ra_*`, content-hash classes from the deployment's
  `dsh-client-ui-model-selection` build). Trigger, Model/Effort cells, provider
  group titles, options, selected check, loading/error/warning strips: all are
  the product's real markup and real styles. A copy of the shipped stylesheet
  is kept in `shipped.css` for provenance.
- The **only** new CSS rules are the `dshmf-*` classes for the added row and
  its highlight state, written from the same design tokens and idioms: 10px
  control radius, caption tone placeholder, subtle borders, hover fill, and the
  trigger's 2px focus ring. They ship as one deduped
  `<style data-plugin-css>` tag owned by the plugin fiber.
- All menu strings come from the shipped `model` locale namespace; the filter
  row registers its own tiny `models-filter` namespace (en + zh).

## Package layout

| File                | Purpose                                                                 |
| ------------------- | ----------------------------------------------------------------------- |
| `package.json`      | The `dsh` manifest: `bundle.patch` + `client` declaration.              |
| `cordis.patch.yml`  | Bundle patch layer: inserts the discovery host row.                     |
| `lib/index.js`      | Host half (GENERATED from `src/index.ts`) — a deliberate no-op marker plugin (see below). |
| `lib/client.js`     | Browser half (GENERATED from `src/client.ts`) — committed lazy-CJS bundle served at `/plugins/dsh-models-filter/client.js`. |
| `src/client.ts`     | Readable TypeScript source of the client half: the factory body plus the type declarations the build erases. |
| `src/index.ts`      | TypeScript source of the host half.                                     |
| `scripts/build.mjs` | Transpiles `src/*.ts` into the committed `lib/*.js` (types erased, comments kept). |
| `tsconfig.json`     | Strict `tsc --noEmit` configuration for `pnpm typecheck`.              |
| `shipped.css`       | Extracted shipped stylesheet kept for class-fidelity provenance.        |

## How it wires into a profile

Three declarations make the package a real bundle rather than a plain
dependency:

1. **`"dsh": { "bundle": { "patch": "./cordis.patch.yml" } }`** —
   `dsh plugin add` reconciles installed dependencies against
   `dsh.profile.bundles`; declaring a patch is what turns this package into a
   profile layer instead of printing the "declares no dsh.bundle" warning.
2. **The patch inserts one loader row** (`id: models-filter`,
   `name: dsh-models-filter`). The web client-module scan discovers browser
   bundles by walking activated loader entries and matching each entry's name
   against installed packages declaring `dsh.client` — without this row the
   client half would never join the boot graph. The host half itself is a
   no-op marker; all behavior lives client-side over services the web surface
   already mounts (`slots`, `locale`, `modelDirectories`, `sessions`).
3. **`"dsh": { "client": { "platform": "web", ... } }` + `exports["./client"]`**
   — once the entry activates, the scan resolves this manifest and adds the
   bundle to the `window.__DSH_BOOT__` graph. The vendored client Loader then
   imports it like any shipped client plugin: the factory runs once,
   returning `{ inject, apply }`; Cordis fiber governance (service waiting,
   stop/update disposal) applies unchanged.
4. **The seat is shadowed at `priority: -1`, never replaced.** The composer's
   model seat is a *single* slot that admits one registration per priority —
   the shipped `dsh-client-ui-model-selection` seat holds priority 0, so this
   bundle registers one priority lower (lower renders) and the shipped entry
   stays registered but dormant. Unloading or disabling this plugin disposes
   its `-1` entry and the shipped seat takes back over with no gap.

## Development

Sources are TypeScript; the committed `lib/` artifacts are generated from them
by transpilation (type annotations erased, comments and runtime code kept
verbatim), which is why installs never run a build and the package has zero
runtime dependencies.

```sh
pnpm install          # runtime deps: none — devDependencies (typescript) serve build/typecheck only
pnpm typecheck        # tsc --noEmit over src/ (strict)
pnpm build            # regenerate lib/client.js + lib/index.js after editing src/*.ts
```

`link:`-style installs (`add ./dsh-models-filter`) symlink the checkout, so a
rebuild plus a profile restart picks edits up immediately. Commit regenerated
`lib/` files before publishing.

## Known deviation

On a rejected selection the shipped component raises a transient Toast; this
plugin leaves the menu open instead. Load errors keep the shipped inline Retry
strip.

## License

[MIT](./LICENSE)

# Author

@odelbos (with GLM-5.3-FLASH)

Install

dsh plugin --profile web add github:odelbos/dsh-models-filter#88a2e229d9a1afad4ecc37cda72d5e6a7f04add3

Profile: web

  • This package builds from source on install. pnpm will ask you to allow its build script — that is permission to run the package’s code on your machine, outside the agent sandbox. Only allow sources you trust.
Source