dsh-local-search
Verified@fishdivinity/dsh-local-search · v0.3.1 · MIT · Web UI
Local file and document search for DeepSeek Harness: Everything filenames plus Anytxt document contents, read-only, with a configuration page on the Plugins page.
Install
dsh plugin add @fishdivinity/dsh-local-search Confirm the layer applied with dsh --profile default --dump-config — see the install guide.
Source
Tags
Creators
Readme
Local Search for DeepSeek Harness
Read-only Everything filename search and Anytxt document-content search, behind one capability-based tool surface.
Contents
- Tools
- Requirements
- Install
- Configuration
- Scopes
- Engine selection
- Errors
- Security and limits
- Known limitations
- Related plugins
- Development
- License
Tools
| Tool | Engine | Use for |
|---|---|---|
local_search_files |
Everything via es.exe |
File/folder names, paths, cross-drive discovery |
local_search_content |
Anytxt JSON-RPC | Text inside PDF, DOCX, XLSX, PPTX, EPUB, RTF, TXT, MD |
local_search_fragments |
Anytxt | Snippets around a match in one indexed file |
local_search_read |
Anytxt | Extracted plain text of one indexed file, capped |
local_search_status |
both | Check whether each engine is reachable |
Requirements
- Windows.
- DeepSeek Harness
>=0.2.1-0 <0.3.0. - Everything running, plus
es.exe(a separate download from voidtools; the plugin auto-detects PATH/common install folders, or setfiles.everything.esPath). - Anytxt Searcher for content search: the GUI (
ATGUI.exe) must be running because the JSON-RPC service lives inside it. The indexing service alone is not enough.
This plugin does not bundle Everything, es.exe, or Anytxt. Install and license them separately.
Install
dsh plugin --profile desktop add @fishdivinity/dsh-local-search
From GitHub before the first npm release:
dsh plugin --profile desktop add github:fishdivinity/dsh-local-search
Restart the profile or open a new session. The five local_search_* tools appear in the model toolset.
Configuration
Sidebar Plugins → the Local Search card in the Official plugins group → the plugin's own page. That is the same card shape the GitHub plugin contributes. Saves apply to the next tool call; leaving the page drops unsaved edits. Reset, under the description, first shows what it will clear and only writes once you confirm: the engine and limit settings go, a fresh probe refills them, and the search scopes are left alone because they are paths you typed.
The page is organised by capability: File names and File contents each open with a backend picker and show that backend's fields once it is selected; Search scopes and Limits are the same whichever backend runs, so they close the page. The Host's GET /dsh-local-search/api/describe supplies the sections, the registered backends, the field types and the hard caps, and the page only renders them, so a new backend does not change the page logic.
Test connection sits under the Anytxt endpoint field. It probes the endpoint as typed — nothing has to be saved first — together with Everything, and puts the result and its fix in a dialog that can probe again. The es.exe path in the field is checked too, so a typo there says the file is missing instead of reporting the saved binary as OK. A failing engine gets a link to its official download page; this plugin never bundles, downloads, or installs either product.
A save checks before it writes. When the endpoint or the es.exe path is part of the edit, the page probes them first: whatever the check refuses is not written, and a dialog asks whether to Save anyway — a deliberate exception rather than the default. A hard rejection (no file at that path, no such directory, a rejected address) gets no such way out. The Host only checks that the path exists; it never starts a file named by a request. Path fields and the endpoint are also checked when focus leaves them: a missing path, a directory where a file belongs, or a non-local address is flagged under the input and clears as soon as the value changes.
Path fields are rewritten to one standard spelling on save: d:/alpha is stored as D:\alpha (upper-case drive letter, backslashes, no trailing separator), and allRoots is rewritten entry by entry. When the path exists, the on-disk spelling wins (d:/alpha → D:\Alpha). Spaces and non-ASCII names are left alone — D:\Alpha\我的项目\drawio a is fine as typed, because the Host passes values to es.exe and the file APIs without going through a shell.
The first run fills what it can and then stops: while files.everything.esPath or content.anytxt.url is still unset, the plugin probes once, writes what answered, and records that pass in a hidden autoConfigured key. After that a field you clear stays clear instead of being filled again.
Every key is optional, and the row config replaces the whole config object rather than merging. Only timeoutMs stays in the profile's cordis.patch.yml: each tool fixes its deadline when it registers, so the page leaves it out rather than showing a field that would not take effect.
| Key | Default | Meaning |
|---|---|---|
files.backend |
everything |
Filename backend auto uses. |
files.everything.esPath |
auto-detect | Absolute path to es.exe. Resolution order: the configured value, ES_PATH, common install folders, where.exe. |
files.everything.esEncoding |
gbk |
Code page used to decode es.exe output. Any TextDecoder label is accepted; the page offers gbk and utf-8. |
content.backend |
anytxt |
Content backend auto uses. |
content.anytxt.url |
http://127.0.0.1:9920 |
Anytxt JSON-RPC endpoint on this machine (127.0.0.1, localhost or [::1] only). The default also tries :9921. |
scopes.workspaceRoot |
session default directory | Root for scope=workspace. |
scopes.workRoot |
empty | Root for scope=work; required before using that scope. |
scopes.personalRoot |
empty | Root for scope=personal; required before using that scope. |
scopes.allRoots |
C:\ plus D:\ when present |
Semicolon-separated roots for Anytxt scope=all. Everything scope=all searches all volumes it indexes. |
limits.maxResults |
20 |
Default result cap; hard cap 100. |
limits.readMaxChars |
8000 |
Default local_search_read window; hard cap 20,000 characters. |
timeoutMs |
30000 |
Per-call timeout budget; profile YAML only. |
Example row override:
- id: fishdivinity-local-search
name: '@fishdivinity/dsh-local-search'
config:
scopes:
workRoot: 'D:\Projects'
personalRoot: 'D:\Documents'
limits:
maxResults: 50
A 0.2 profile needs no hand edit: on startup its nine flat keys (esPath, esEncoding, anytxtUrl, workspaceRoot, workRoot, personalRoot, allRoots, maxResults, readMaxChars) move into the structure above and are removed. When the settings layer refuses that write — a home patch overrides the profile — the old keys stay and are still read.
Scopes
workspace(default): the session's working directory.work:scopes.workRoot.personal:scopes.personalRoot.all:scopes.allRootsfor Anytxt; all indexed volumes for Everything.
Use all only when the user explicitly asks for a cross-drive/global search. The path argument overrides scope.
Engine selection
engine defaults to auto, which follows the backend configured for that capability: files.backend for local_search_files, content.backend for local_search_content, fragments, and read.
local_search_files:autooreverything.local_search_content/fragments/read:autooranytxt.local_search_status:auto,everything, oranytxt.
The tool names stay stable if more engines are added; engine values are additive. Content items carry both engine and a self-describing ref such as anytxt:123; pass the ref unchanged to local_search_fragments/local_search_read, and pass engine only as an assertion.
Errors
Failures are typed HarnessErrors with stable codes:
| Code | Meaning |
|---|---|
EVERYTHING_ES_NOT_FOUND |
es.exe is missing; install it or set files.everything.esPath. |
EVERYTHING_DOWN |
Everything is not running / cannot be reached. |
EVERYTHING_TIMEOUT, EVERYTHING_TOO_LARGE |
Query too broad or slow; narrow it. |
ANYTXT_DOWN |
Anytxt GUI is not running or the JSON-RPC endpoint is unreachable. |
ANYTXT_TIMEOUT, ANYTXT_RPC, ANYTXT_HTTP |
Anytxt-side query/transport failure. |
ROOT_NOT_FOUND, SCOPE_NOT_CONFIGURED, INVALID_SCOPE |
Root/scope configuration problem. |
INVALID_ARGUMENT |
Empty query, bad limit, etc. |
If a search reports *_DOWN, fall back to grep/glob and say that you fell back.
Security and limits
- Read-only: no write, delete, index-sync, OCR, export, or settings operation is registered.
es.exeis always spawned with a fixed argv; model text goes after--, so-export-*,-save-settings,-clear-settings,-exit,-reindex,-save-db, and run-count switches are unreachable.- Anytxt is only called through
Search,GetResult,GetFragmentAll, andGetRawTextByFID. - No network access except the configured local Anytxt URL.
- Results are capped;
local_search_readcaps the returned text. - The plugin runs with the user's privileges and can read files the user can read. Prefer
scope=workspaceunless a global search is requested.
Known limitations
- Windows only.
- Everything 1.4 indexes metadata, not file contents; use Anytxt for contents.
- Anytxt's JSON-RPC API is local and unofficial; GUI versions can change behavior. The plugin reports unreachable/wrong-shape responses instead of guessing.
- Anytxt's index may be stale. Verify important hits with
read/the original file. - No auto-start: starting
ATGUI.exewrites the index and is left to the user. - Anytxt's terms limit personal/non-commercial use; commercial use needs its own license.
Related plugins
dsh-tool-everythingcovers Everything filename search through the SDK.dsh-workspace-searchcovers workspace file names/contents in the sidebar.- This plugin's differentiator is Anytxt document content plus one routing surface for names and contents.
Development
No dependencies; tests use Node's built-in test runner.
npm test
npm run check
npm run pack:check
The engine and config modules (lib/everything.js, lib/anytxt.js, lib/roots.js, lib/format.js, lib/config.js) are independent of the DSH runtime so their tests run under plain Node. lib/client.js ships as the browser half: it is written directly in the client module system's lazy-CJS factory format, so there is no build step. See docs/architecture.md, docs/extending-engines.md, docs/config-migration.md for the rules a config-shape change has to follow, and .github/RELEASING.md.
Changelog
See CHANGELOG.md (Chinese) or CHANGELOG.en.md (English). They stay in the repository; the npm tarball ships only the runtime files, README, LICENSE, locale, and icon.
License
MIT. Everything and Anytxt are separate products with their own licenses and trademarks; this project is not affiliated with voidtools or CBEWIN.