# dsh-skill-fuzzy Codex-style fuzzy skill search for the DeepSeek Harness Web GUI. The built-in `/` skill menu only matches skill-**name prefixes** (`startsWith`); this plugin makes it search the way Codex does: | Query | Result | |---|---| | `/diag` | `diagnosing-bugs` (name prefix) | | `/bug` | `diagnosing-bugs` (name substring) | | `/bu` | `diagnosing-bugs` (name contiguous substring) | | `/regression` | `diagnosing-bugs` (**description** term) | ## Matching & ranking - **Names** — port of Codex's `fuzzy-match`: greedy, case-insensitive **ordered-subsequence** matching with a window + start-of-string-bonus score (smaller is better; prefix hits dominate). - **Descriptions** — matched as **contiguous, case-insensitive substrings** only (deliberately tightened after field testing: scattered subsequences across a long description surfaced noise, e.g. `/m01` hitting a skill whose description merely contains an `m…0…1` spread). - **Ordering** — name-hits first → score ascending → stable roster order. Empty query returns the full roster unchanged (prefix behavior never regresses). ## Install ```sh dsh plugin --profile web add /path/to/dsh-skill-fuzzy # or from GitHub: dsh plugin --profile web add github:ch1bug/dsh-skill-fuzzy ``` Restart `dsh web` and hard-refresh the GUI (the boot manifest is injected at page load), then type `/` and search. ## How it works A **web-client-only** plugin. It wraps the built-in `/` skill source's `candidates()` — found via `inputTriggers.live.sources` (the service's public face is `{ctx, name, live}` + prototype `{registerSource, sessionOf, sessions}`; there is no `all()`/`sources()` accessor on the service — those live on the menu controller's internal roster). The wrapper calls the original `candidates` with an empty query to obtain the full roster (preserving the `skill.list` RPC, user-only markers and abort semantics), then filters/ranks it. `registerSource` is patched as a guard for late re-registrations. ## Development ``` lib/fuzzy.js Codex fuzzy-match port (fuzzyMatch) lib/skill-rank.mjs ranking (rankSkills) lib/client.js self-contained browser half (inlines both; pinned by tests/sync.test.mjs against the tested modules) tests/ node:test suite — node --test tests/fuzzy.test.mjs tests/skill-rank.test.mjs tests/sync.test.mjs ``` The client bundle route serves a single `client.js` per plugin, so the pure logic is inlined there and kept in sync with the tested modules by `tests/sync.test.mjs`. ## License MIT. The `fuzzyMatch` algorithm is a port of [`codex-rs/utils/fuzzy-match`](https://github.com/openai/codex/blob/main/codex-rs/utils/fuzzy-match/src/lib.rs) from [openai/codex](https://github.com/openai/codex) — see [NOTICE.md](NOTICE.md).