dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
Web GUI 的快速打开面板:Ctrl+P 在会话工作区的内存索引上做模糊检索(约 5.1 万条目,查询中位数 5 ms),支持逐段路径锚定、dir: 与 file: 前缀、Tab 目录下钻与 :行号 跳转;选中文件走 DSH 原生右栏打开,Ctrl+Enter 把文件引用放进会话草稿。另为内置文件预览补上文件内查找(Ctrl+F)与选中加入会话。
Fast file navigation and referencing for DSH: VSCode-style Ctrl+P quick open, plus two missing pieces of the built-in file preview — find-in-file and add-selection-to-conversation.
Median hot query over a 50,000-file workspace: 5 ms (reproduce with
node scripts/bench.mjs).
English | 中文

Tab does more than complete a path: landing on a directory swaps the list for that directory's direct children (directories first, then sibling files), so you can drill down one level at a time; keep typing and you are back to fuzzy filtering. Key hints and index transparency (entry count · freshness) stay pinned to the footer.
1. Finding a file in a large repository is slow, and the names are unguessable.
Production repositories run to tens of thousands of files, and nobody remembers how to spell client_module.cpp. This plugin ports VSCode's quick-open fuzzy scorer verbatim — clntmod finds client_module.cpp — over a per-workspace in-memory index, so results appear as you type. Path queries containing / are anchored segment by segment (login/index.html will not assemble a false hit by borrowing one letter from each of five unrelated directories), and the dir: / file: prefixes scope a term precisely.
2. Your code does not live in one repository.
Engine, game, and protocol repositories sit side by side, and chasing one issue means hopping between them. Extra index roots (extraRoots) fold any number of directories outside the workspace into the same index — one Ctrl+P searches every repository, result rows carry a source badge (engine/_source, game/_content, …), and references switch to absolute paths automatically. No second window, and no remembering which repository a file belongs to.
3. Feeding code context to an AI conversation takes too many steps.
Find file → open → select → copy → switch back to the composer → paste → fix the path… This plugin compresses that into two gestures: Ctrl+Enter drops the file into the draft as an @ reference (the palette stays open, so you can add several in a row); and selecting code in the file preview and clicking the floating "Add to conversation" inserts a precise @path:start-end reference.
4. The built-in DSH file preview cannot search.
The built-in preview renders everything (code highlighting, Markdown, HTML, PDF, images) except find-in-file. This plugin adds a Ctrl+F floating find bar that highlights matches uniformly across every renderer, with case sensitivity, selection prefill, and a "loaded part only" notice. It takes over nothing and replaces nothing: uninstalling restores the stock preview exactly.
Ctrl+P)Summoned from any session page, with strict focus discipline (keyboard focus never leaves the search box):
| What you want | How |
|---|---|
| Fuzzy-find a file | Just type, e.g. clntmod matches client_module.cpp |
| Locate by directory | ui/index.html (anchored per segment, so no false hits) |
| Jump to a line | main.cpp:120 (the built-in preview scrolls to and highlights that line) |
| Scope a term precisely | dir:ui index.html (ui must be a directory segment), file:index.html (filename only); shorthand d: / f: — see below |
| Reopen the last file | Ctrl+P → Enter (an empty query shows recently used) |
| Drill into directories | Tab completes; a directory keeps its trailing / and can be pressed repeatedly |
| Reference into the conversation | Ctrl+Enter, or click "+ Reference" at the row's end — the palette stays open, so you can add several |
| Open the file | Enter — goes through DSH's native right Sidebar, the same path a file-tree click takes |
Ctrl+P / Ctrl+F / Ctrl+Enter, or Cmd on macOSAll three actions can be rebound, with defaults that match each platform's habits:
| Action | Default | Notes |
|---|---|---|
| Open the quick-open palette | Ctrl+P / macOS Cmd+P | Works on any session page; press again to close |
| Search within the file preview | Ctrl+F / macOS Cmd+F | Applies while the sidebar preview has focus; opens the floating find bar |
| Add the highlighted file to the conversation | Ctrl+Enter / macOS Cmd+Enter | Hold the modifier and press Enter inside the palette; the reference lands in the draft and the palette stays open |
Open the settings page, click the record button, and press the new combination once — it takes effect immediately, with no reload.
Two design decisions:
Enter may be the main key on its own). Bare-letter bindings are refused, because they would fire while you type; the recorder rejects them outright and explains why.⚠️ macOS users: earlier versions accepted either
Ctrl+PorCmd+P; the default now recognisesCmd+Ponly. If you are used toCtrl+P, re-record it on the settings page (or just adoptCmd+P, which is the macOS standard).
dir: and file: — scoping where a term is allowed to matchA query is split on spaces into terms, and each term may carry a prefix restricting which part of the path counts as a match:
| Spelling | Meaning | Example |
|---|---|---|
dir:ui | Must match a directory segment; the filename does not count | .../ui/coherent/bag/index.html ✓ui_helpers.cpp (ui only in the filename) ✗ |
file:main.cpp | Must match the filename; directories do not count | .../camera/main.cpp ✓.../main.cpp/helper.txt ✗ |
d: / f: | The same, abbreviated | d:ui f:index.html |
| no prefix | Filename first, falling back to the whole path for path queries | clntmod, ui/index.html |
Prefixes mix freely, each term governing itself:
dir:camera file:manager a camera segment in the path, and "manager" in the filename
dir:client cpp client must be a directory segment; cpp fuzzy-matches the filename as usual
Two properties, confirmed by measurement:
dir:camera highlights only camera/ in the path and not a single letter of the filename; file:camera is the reverse. The highlight tells you which term matched where.dir: requires the directory name to appear contiguously; file: allows abbreviations. This asymmetry is deliberate: directories are targeted by typing their name (dir:camera will not match .../chaos_client_camera_effect_manager.cpp, whose filename merely contains "camera"), whereas filenames are usually reached by abbreviation (file:clntmod matches client_module.cpp).
So dir:clntmod finding nothing is expected — no directory segment contains those letters contiguously. Use file: or no prefix to abbreviate a filename.With no prefix, dir: / file: change nothing: clntmod, ui/index.html, and main.cpp:120 all behave as before.
extraRoots)Fold any directory outside the workspace into the same index, so multi-repository work needs no context switching:
{
"extraRoots": [
{ "path": "E:\\dev\\engine\\_source", "label": "engine" },
{ "path": "E:\\dev\\game\\_content", "label": "game" }
]
}
Ctrl+P searches every root; result rows carry a source badge, so a deep path is still instantly attributable to a repository@E:/dev/engine/...) automatically, and the AI can read it as usualbuild is not caught by the workspace's own build excludeThe built-in preview keeps its renderer switching, paged loading, change notices, line wrapping, and line jumps. This plugin adds exactly two things:
Find in file (Ctrl+F)
Enter / Shift+Enter step through matchesCtrl+F, and it is prefilled as the queryAa case-sensitivity toggle that remembers your preferenceEsc closes it from anywhere (no need to click back into the search box first)Select to reference
@relative/path:start-end reference is inserted@path when the renderer exposes no line numbers)dsh plugin --profile web add dsh-quick-open # from npm
dsh plugin --profile web add github:asxiuxiu/dsh-quick-open # from GitHub
dsh plugin --profile web add link:D:/dev/dsh-quick-open # local development
Restart DSH after installing (the host half mounts only at boot). It depends on DSH itself and on no third-party sidebar plugin.
The peer declarations cover DSH 0.1.5-rc.1 through 0.2.x (excluding 0.3.0):
@deepseek-ai/dsh-client-ui-slots >=0.1.5-rc.1 <0.2.0-0 || >=0.2.0-rc.1 <0.3.0-0 || >=0.2.1-alpha.1 <0.3.0-0
@deepseek-ai/dsh-client-ui-conversation >=0.1.1-rc.1 <0.1.2-0 || >=0.1.2-rc.1 <0.1.3-0 || >=0.1.5-rc.1 <0.2.0-0 || >=0.2.0-rc.1 <0.3.0-0 || >=0.2.1-alpha.1 <0.3.0-0
@deepseek-ai/dsh-client-ui-sidebar-right >=0.1.5-rc.1 <0.2.0-0 || >=0.2.0-rc.1 <0.3.0-0 || >=0.2.1-alpha.1 <0.3.0-0
@deepseek-ai/cordis ^4.0.2
Why the range is this "union of lanes" rather than a single >=0.1.5-rc.1 <0.3.0: per the semver
spec, a prerelease version only satisfies a range when a comparator in the same tuple carries a
prerelease tag. DSH ships its client packages on 0.2.0-rc.N / 0.2.1-alpha.N prerelease lanes,
so the upper bound must carry -0 and every prerelease lane has to be listed explicitly —
otherwise npm judges those versions unsatisfied.
⚠️ Releases up to and including 0.3.0 declared
>=0.1.5-rc.1 <0.2.0-0, which shut out both0.1.7-rc.*and0.2.x. Once DSH moved to 0.1.7 / 0.2.0 the market refused to install it outright ("host incompatible"). When an install is refused, check this section first.
It works out of the box: with no config file it uses built-in language-neutral, project-neutral defaults (excluding only the noise directories every ecosystem agrees on, plus source extensions common across languages).
To customize, open Settings → Quick Open index and edit the current workspace's .dsh/quick-open.json:
{
"version": 1,
"excludeDirs": ["_install", "build/Engine"], // bare name at any depth; with a slash, anchored to the root; **/ for any depth
"includeDirs": ["build/p/include"], // takes precedence over excludes — rescues a wrongly swept generated tree
"includeExtensions": [".h", ".cpp", ".py", ".md"],
"includeFilenames": ["CMakeLists.txt"],
"includeDirectories": true,
"extraRoots": [ // directories outside the workspace, indexed together
{ "path": "E:\\path\\to\\sibling-repo\\_source", "label": "sibling/_source" }
]
}
Saving is atomic, takes effect within 3 seconds, and needs no restart. Why the rules are stored per workspace, the inherent blind spot of an extension allowlist, and why includeDirs can rescue a generated tree — see the architecture section below and docs/.
fuzzyScorer.ts + filters.ts, with constants and score tiers taken from the source). Eight original schemes were tried first, and every one broke on another set of queries; VSCode's 1<<16-scale tiering fundamentally guarantees that "matched the filename" always outranks "matched the path" — there are no weights to tune. Experiments and negative results: docs/matching-research.mdlogin/index.html measured 27,002 scattered false hits (52.7% of the index), burying the correct answer in 130:1 noise; anchored, it converges from 620 candidates to 7, all correctreaddir builds a per-workspace in-memory index, kept fresh by a 30 s TTL with stale-while-revalidate, noticing config changes within 3 seconds, with atomic config writesnpm install
npm run build # emits lib/index.js (host: the index routes) + lib/client.js (the __ModuleLoader__ envelope, ~80KB)
npm run typecheck
npm run check # typecheck + peer ranges + build + the client-bundle suite
# Verification scripts
node scripts/check-peer-ranges.mjs # peer ranges actually accept the lanes they claim (0.1.x / 0.2.x)
node scripts/verify-i18n.mjs # key parity, no untranslated/empty values, placeholder survival
node scripts/verify-client-bundle.mjs # end-to-end stub test of the built artifact (incl. Ctrl+P being claimed)
node scripts/verify-grammar.mjs # dir:/file: prefix parsing boundaries
node --experimental-strip-types scripts/verify-file-address.mjs # file addresses / @ references / :line suffix
node --experimental-strip-types scripts/verify-preview.mjs # preview-augmentation pure logic
node scripts/verify.mjs # match-quality regression
node scripts/verify-no-regression.mjs # per-case comparison of separator-less query behaviour
node --expose-gc scripts/eval-cost.mjs # index size baseline
node scripts/eval-ambiguity.mjs # quantifying directory-name ambiguity
Some scripts (
verify.mjs,verify-children.mjs,verify-drill.mjs,verify-no-regression.mjs) read a real workspace at a hardcoded path and exit withENOENTunless that path exists. Point them at your own checkout before running.
src/rules.ts index rules: directory matching (subtree semantics + **/ globs) / file filtering / config parsing
src/match.ts the VSCode scorer port + dir:/file: scope-prefix parsing
src/index.ts host half: /quick-open/api/{search,children,probe,config.get,config.set,config.reset}
src/client/index.tsx client entry: global shortcut listener + preview-augmentation mount + slot registrations
src/client/i18n.ts every user-visible string, in English and Chinese, with language resolution
src/client/controller.ts the search pipeline (query cache / index route / directory drill), :line parsing, open, reference, recents
src/client/quick-open.tsx the palette component (portal to body, z-index 10000, multi-segment highlighting)
src/client/settings.tsx settings panel: index rules + reference format + shortcut recording
src/client/shortcut.ts shortcuts: cross-platform primary-modifier mapping, matching, recording, validation, persistence
src/client/preview/ preview augmentation: find bar (Highlight API) + selection popup + DOM probing (all gracefully degrading)
docs/ matching research, directory-filter evaluation, sidebar integration research, architecture notes (with measurements and negative results)
The plugin ships English and Chinese. Language follows the DSH shell's own locale preference (<html lang>), is re-read on every lookup so switching needs no reload, and anything that is not zh* resolves to English.
Every user-visible string lives in one table, src/client/i18n.ts. That is enforced rather than merely intended:
Messages, so a key added to English and forgotten in Chinese is a compile errorscripts/verify-i18n.mjs asserts key parity, rejects empty values, rejects a Chinese value identical to its English counterpart (a forgotten translation), and requires every {placeholder} to survive translationverify-i18n.mjs covers that too%query prefix switching to content searchCtrl+Space to mark several rows and add them in one actionfs.watch invalidation: keep the index live with file changes (replacing or supplementing the TTL)dir: queries: an inverted index over directory segments (+4.3 MB, 19% of the total index), see docs/dir-filter-evaluation.mdMIT