beijingwahw/dsh-conv-search
dsh-conv-search(对话内文本搜索)— 适用于DeepSeek Harness的对话内文本搜索插件(Ctrl+F,区分大小写,全词匹配,支持流式感知)
项目介绍Project Overview
为 DeepSeek Harness 网页界面提供对话内文本搜索插件。核心能力是 Ctrl/Cmd+F 唤起浮层搜索栏,仅作用于当前对话渲染区,使用 CSS Custom Highlight API 上色高亮,避开 React 管理文本。适用于长会话中定位错误码、函数名或某次回复等场景,按 Enter 与 Shift+Enter 在匹配项间循环切换。注意:仅支持纯文本匹配,跨样式标签的短语不命中,且依赖较新版浏览器。
A web UI plugin for the DeepSeek Harness that adds in-conversation text search. It opens a floating bar on Ctrl/Cmd+F, scoped to the active chat, and paints matches through the CSS Custom Highlight API so highlights survive React re-renders and streaming. Use it to locate error codes, identifiers, or earlier replies inside long sessions, navigating with Enter and Shift+Enter. Caveat: matching is plain text only, cross-span phrases are not detected, and the feature requires browsers with the CSS Custom Highlight API.
请帮我了解并安装插件:【dsh-conv-search】【https://github.com/beijingwahw/dsh-conv-search】
把上面这条消息直接发给当前会话里的 DSH,让它帮你了解并安装。安装命令不一定准确,发给 DSH 更稳。Send this message to DSH in your current session. CLI install commands may not be accurate across systems — DSH will figure it out for you.
或使用命令行安装(适合开发者)Or use CLI install (for developers)
命令行安装CLI Install
dsh plugin add beijingwahw/dsh-conv-search --profile web
把 beijingwahw/dsh-conv-search 加入你的 DSH 配置(web profile)即可启用。
READMEREADME
dsh-conv-search(对话内文本搜索)
English | 中文
In-conversation text search for the DeepSeek Harness web UI — the Ctrl+F you already know, scoped to the current chat session. A floating search bar highlights every match in the rendered transcript and walks between them, without touching a single line of harness core code.
Problems it solves
- Long sessions are unsearchable: the browser's native find searches the whole page (sidebar, composer, chrome) and cannot follow a conversation that keeps streaming. This plugin searches only the active conversation scrollport and stays in sync while the model is still writing.
- No way to jump between occurrences: native find gives no "n / total" navigation. This plugin provides Enter / Shift+Enter and prev/next buttons with wrap-around, centering each match in view.
- Highlighting must not fight React: the transcript DOM is React-owned and re-renders continuously during streaming. Instead of wrapping matches in
<mark>nodes (which would mutate React-managed text and break reconciliation), the plugin paints ranges through the CSS Custom Highlight API — an overlay that survives every re-render and needs zero DOM cleanup.
Features
- Ctrl/Cmd+F opens the floating search bar (only when a conversation is rendered — otherwise the browser's native find stays untouched); Esc closes it from anywhere, including while the input holds focus.
- Matching across every rendered chat node: user messages, assistant text, tool cards, and paged-in history. Two toggles mirror the browser/IDE find bar: Aa (match case) and ab (whole word) — essential for hunting error codes, function names, and API identifiers.
- Live
n / totalcounter with Enter (next) / Shift+Enter (previous) navigation and wrap-around; F3 / Ctrl+G work too, the browser/IDE find-bar convention. - Query history: ArrowUp / ArrowDown cycle through your recent queries (most recent first, deduplicated), restoring the draft you were typing when you walk back past the newest entry.
- Zero-result queries answer back: the count turns red, the bar border follows, and the bar gives a one-shot shake (honoring
prefers-reduced-motion). Repeated Enter on no results re-shakes instead of staying silent. - The active match is painted in a stronger color and scrolled into view automatically.
- The header action button mirrors the open state (
aria-pressed), so you always know whether search is active. - Streaming-aware: a MutationObserver re-runs the search (debounced) while output streams or older pages load, without stealing your scroll position. The active match is anchored by identity (text node + offset), so a paged-in older page or a streamed delta never jumps your cursor to a different occurrence.
- Scope discipline: the composer seat and the plugin's own bar are excluded, so your draft text never produces phantom hits.
- Follows the harness theme through
--dsw-alias-*design tokens; Chinese/English UI picked from the document language. - Session header action button (search icon) registered through the
conversation.session.header.actionsslot — the additive, unload-safe composition route.
Install
Requires Node.js ≥ 22 and pnpm (npm install -g pnpm) — dsh plugin add installs the bundle into the profile with pnpm.
One-liner
dsh plugin add beijingwahw/dsh-conv-search --profile web
dsh web # restart the server to pick the plugin up
Common follow-ups: upgrade
dsh plugin upgrade dsh-conv-search --profile web; uninstalldsh plugin remove dsh-conv-search --profile web; local-path installdsh plugin add ./dsh-conv-search --profile web.
The package declares dsh.bundle.patch (mounts the host registration row) and dsh.client (serves the browser half at /plugins/<id>/client.js). lib/ is committed, so the GitHub tarball installs without a build step.
Verify the mount:
dsh --profile web --dump-config | grep conv-search
Usage
| Gesture | Action |
|---|---|
Ctrl/Cmd+F (or the header search icon) |
Open the search bar |
| Type | Search as you type (120 ms debounce) |
Enter / F3 / Ctrl/Cmd+G |
Next match (wraps) |
Shift+Enter / Shift+F3 / Ctrl/Cmd+Shift+G |
Previous match (wraps) |
ArrowUp / ArrowDown |
Browse previous queries |
Aa / ab buttons |
Match case / whole word |
Esc |
Close and clear all highlights |
How it works
src/client/engine.ts— pure DOM helpers: text-node walk, case-insensitive range matching,CSS.highlightspaint (dsh-conv-searchfor all matches,dsh-conv-search-activefor the focused one), and scroll-into-view. No cordis, no React — unit-testable against jsdom.src/client/controller.ts— the floating bar (plain DOM, so it never couples to the shell's React version), keyboard capture, debounced search passes, and the transcript MutationObserver that keeps highlights honest during streaming.src/client/index.ts— the cordis client half: installs the controller throughctx.effectand registers the header action button viactx.slots.inject('conversation.session.header.actions', ...), so the button appears and disappears with the slot declaration and plugin fiber.src/index.ts— the host half is an empty registration shell; all behavior is browser-side.
Model Experience
None. The plugin only reads the rendered transcript in the browser; it touches no prompt, message, schema, stream, tool, or provider request.
Development
pnpm install
pnpm run typecheck # strict TS, no emit
pnpm run build # tsdown: host ESM + browser client bundle, then tsc for declarations
pnpm test # vitest (jsdom): engine, controller, i18n
The client bundle enforces the harness purity rule: platform modules (react, cordis, the seeded client packages) stay externals, and any other @deepseek-ai/* value import fails the build.
Known Limitations and Deferred Work
- Matching is plain-text only — no regex, no diacritic folding, no cross-node phrase matching (a phrase split across styled spans will not match).
- Requires a browser with the CSS Custom Highlight API (Chrome/Edge 105+, Safari 17.2+, Firefox 132+). On unsupported browsers the bar still counts matches but paints no highlight.
- The bar position is fixed (
top: 64px; right: 24px); it is not draggable yet. - Search scope is the active conversation column only — sidebar session titles and settings pages are intentionally out of scope.
Troubleshooting
'pnpm' is not recognizedduringdsh plugin add→ install pnpm first:npm install -g pnpm.EADDRINUSE ... :3080ondsh web→ a previousdsh webis still bound to the port. Stop it (Ctrl+C in its terminal; on Windows:Get-NetTCPConnection -LocalPort 3080 | ForEach-Object { Stop-Process -Id $_.OwningProcess -Force }), or start on another port withdsh web --port 3081.
License
MIT
ruvnet/ruflo
amruthpillai/reactive-resume
volcengine/OpenViking
Molunerfinn/PicGo
titanwings/colleague-skill
nocobase/nocobase
Tencent/WeKnora