# dsh-task-plugin-scout **English** | [中文](README.md) [![npm version](https://img.shields.io/npm/v/dsh-task-plugin-scout.svg)](https://www.npmjs.com/package/dsh-task-plugin-scout) [![license](https://img.shields.io/npm/l/dsh-task-plugin-scout.svg)](LICENSE) A [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (DSH) plugin that answers one question before work starts: **which plugins already available to this profile would make the task at hand easier?** It registers one model-facing tool, `plugin_scout`, plus a short system-prompt section that reminds the agent to use it. Given a one-line task description it ranks this profile's plugins — **already active**, **installed but disabled**, and **installable from the configured market indexes** — and returns the exact next step for each candidate (enable, install, or nothing). - Package: `dsh-task-plugin-scout` · loader row: `dsh-task-plugin-scout` - Host-only bundle: no dependencies, no build step, plain ESM JavaScript - Changes nobody's state by itself: it only *recommends*; enabling or installing still goes through `plugin_manager` and the user's approval ## What you get | Part | Name | Purpose | | --- | --- | --- | | Model tool | `plugin_scout` | Ranks plugin candidates for a task and returns each one's next step | | Prompt section | `plugin-scout:discovery` (order 700) | Tells the agent to scout before starting non-trivial work | Example result (numbers are illustrative; each run reports its own `Coverage`): ``` Plugin Scout · task: 把开会录音转成文字纪要 (voice, transcription) Coverage: 3 of the listed candidates need an action to take effect · 48 bundles · 214 plugin rows · 12 market entries · https://example.com/index.json: 12 of 1234 1. 语音输入 [disabled, score 10] — bundle `@deepseek-ai/dsh-experimental-voice-input-bundle` 在本机使用 SenseVoice 转写录音,首次使用需安装依赖。 matched: voice next: plugin_manager { action: "set_bundle", target: "@deepseek-ai/dsh-experimental-voice-input-bundle", enabled: true } ``` `state` is one of: | State | Meaning | Next step | | --- | --- | --- | | `active` | Already running in this profile | none | | `disabled` | Installed but switched off (including shipped opt-in bundles) | `set_bundle` / `set_plugin` | | `available` | Not installed; offered by the Official catalog or a market index | `install_bundle` | ## Install DSH must have `plugin-manager` (standard in shipped profiles), and **DSH ≥ `0.2.1-rc.2`** is required (see `engines.dsh` in `package.json`; developed on `0.2.1-rc.2` and re-verified on `0.2.1-rc.3` — see "Compatibility record" below). Use the `plugin_manager` tool: ```jsonc // 1. from npm (recommended) { "action": "install_bundle", "target": "dsh-task-plugin-scout" } // 2. from Git { "action": "install_bundle", "target": "git+https://github.com/crane-you/dsh-task-plugin-scout.git" } // 3. from a local checkout (absolute path to the package directory) { "action": "install_bundle", "target": "D:\\path\\to\\task-plugin-scout" } ``` npm page: https://www.npmjs.com/package/dsh-task-plugin-scout (or `npm i dsh-task-plugin-scout`). Activation is reported as `application: applied`. Confirm with `cordis_inspect_query` (`Tool.listTools` should list `plugin_scout`) rather than by reading logs. ## Compatibility record | DSH version | Verdict | Basis | | --- | --- | --- | | `0.2.1-rc.2` | Development and test version | All features exercised | | `0.2.1-rc.3` | Re-verified, no code change needed | See below (2026-10-25) | | `0.2.1-rc.4` / `0.2.1-rc.5` | Re-verified again, still no code change needed | See below (2026-10-31) | ### `0.2.1-rc.5` re-verification (2026-10-31) 1. **API surface.** The same six host packages ship **byte-identical JavaScript** across `rc.3 → rc.4 → rc.5`, and `@deepseek-ai/dsh` resolves the same 86 packages on `rc.3` and `rc.5` — **nothing added or removed**, only version references changed. 2. **The host's own gate.** The manifest was judged by `rc.5`'s own `@deepseek-ai/dsh-app-boot` (package version `0.2.1-rc.5`): *compatible*. 3. **Real load.** `rc.5`'s `loadProfileDirectory()` composes this machine's desktop profile with this bundle mounted, all eight external bundles green. 4. **Live check.** After the host was upgraded to `rc.5` and restarted, the `plugin_scout` tool answered (28 bundles / 211 plugin rows / 60 market entries). ### `0.2.1-rc.3` re-verification (2026-10-25) The `0.2.1-rc.3` re-verification did three things: 1. **Byte-level API comparison.** Every host package this plugin touches — `@deepseek-ai/dsh-tools`, `dsh-system-prompt`, `dsh-plugin-manager`, `dsh-plugin-market`, `dsh-plugin-market-index`, `dsh-app-boot` — ships **identical JavaScript** in `rc.2` and `rc.3` (the only differences are version references inside `package.json`). No touchpoint moved: `ctx.tools.register`, `ctx.systemPrompt.section`, `pluginManager.listBundles/listPlugins`, and `pluginMarket.listIndexes/search` keep their fields and signatures (`search` still requires `sort`, `offset`, and `limit`, and still answers with `entries` / `total`). 2. **The host's own compatibility gate.** The plugin manifest was handed to the real `evaluatePluginCompatibility()` in `rc.3`'s `@deepseek-ai/dsh-app-boot`; the verdict is *compatible* (no unmet DSH requirement). That is the very check that makes the host skip an incompatible package while loading a profile bundle. 3. **The bundled harness**: `node test/harness.mjs` passes. `engines.dsh` moved from `>=0.2.0` to `>=0.2.1-rc.2`. The host gate evaluates ranges with `semver.satisfies(…, { includePrerelease: true })`, so it accepted `>=0.2.0` too — but under npm's **default** SemVer rules a prerelease version can only satisfy a range when some comparator shares its `[major, minor, patch]` tuple and carries a prerelease of its own. `>=0.2.0` therefore matches no `0.2.1-rc.x` runtime under the default rules. DSH ships only prerelease lines today, so a prerelease floor makes the declaration true under both rule sets and stops third-party tooling (npm's `engine-strict`, compatibility panels) from misreading it. The cost is that `0.2.0-rc.*` and `0.2.1-rc.1` are now explicitly excluded — they were never in the tested range anyway. ## Tool reference | Argument | Type | Default | Meaning | | --- | --- | --- | --- | | `task` | string, **required** | — | What the user asked for, in one or two lines. Keep the user's own words and add English capability keywords when the task is not in English, because most plugin metadata is English. | | `limit` | integer | `5` | How many candidates to return (1–12). | | `useMarket` | boolean | `true` | Include the configured market indexes. Set `false` for a local, offline answer. | | `includeActive` | boolean | `true` | Whether already-active plugins may be listed. Set `false` to see only candidates that need an action. | ## How ranking works 1. **Capability concepts** — about 35 bilingual concept groups (voice, translation, spreadsheet, image, parallel work, scheduling, notifications, …). When the task hits a concept *and* a candidate's name/title/description/keywords hits the same concept, it scores +6. This is what lets a Chinese task find an English-described plugin, and vice versa. 2. **Literal overlap** — the task is tokenized (Latin words, CJK bigrams); a token in the plugin name scores +3, in its title +2, in its description or keywords +1. 3. **Tie-break by state** — `disabled` → `available` → `active`, so actionable candidates come first. 4. **Matching is boundary-aware** — ASCII concept forms must start at a word boundary, so `transcription` never triggers `script` and `password` never triggers `word`; CJK forms match as substrings. ## Configuration Optional fields on the plugin row's `config` (a profile `cordis.patch.yml` override): | Field | Default | Meaning | | --- | --- | --- | | `promptHint` | `true` | Whether to register the system-prompt section | | `hintText` | built-in text | Replaces the whole prompt section | | `limit` | `5` | Default for the `limit` argument | | `useMarket` | `true` | Default for the `useMarket` argument | The plugin declares no `Config` schema, so the object is read as-is and a misspelled field is not validated. ## Known limits - **Row-level candidates (`kind: plugin`) describe the profile patch layer.** An agent preset can already mount the same row, in which case the capability is effectively present; the tool prints that caveat whenever it lists a disabled row. Bundle-level candidates are not affected. - **Market results need a configured index.** The service mounts with the market bundle, but ships with no index source; until one is added the tool reports `market: no index configured` and falls back to local-only results. - **Market text is third-party content**, not instructions, and indexes are unsigned — the installed manifest decides what actually installs. - **The tool never enables or installs anything** on its own; those steps keep their own approval. ## Privacy - **Nothing is collected or reported.** No telemetry, no analytics, no files written, no memory kept outside the session. All work happens in the Host process against in-memory inventories. - **The task description never leaves the machine.** The only outbound path is the plugin market: the Host downloads the index documents you configured (a plain GET), and `task` is used **locally** to filter the already-downloaded document — the market service caches a document per URL, shares one fetch between concurrent readers of that URL, and never puts query text into a request. Set `useMarket: false` for a fully offline run. - **What enters the session log**: matched plugin names, titles and descriptions, plus the local inventory counts. They are recorded with the tool result in your own session log (for replay and fork); sharing that transcript would disclose your installed-plugin list. `includeActive: false` narrows the result to candidates that need an action. - **Market text is third-party content** and indexes are unsigned; it is presented as a candidate only, and the installed manifest decides what actually installs. ## Development `test/harness.mjs` mounts the bundle on a fake context with fixture inventories and exercises ranking, argument handling, error handling, and the config path — no DSH required: ```bash node test/harness.mjs ``` ## Plugin market The plugin is published to npm, so indexes built from npm metadata pick it up automatically. To search the whole community catalog from DSH's Discover tab, add **dshmarket's community catalog**, which it also publishes as a format-1 index (the same data its own UI shows): ``` https://cdn.jsdelivr.net/npm/dsh-plugin-catalog/index.json ``` Settings → Plugins → **Discover** → add index, paste the URL above. > That document is about 2.2 MiB: on some networks it exceeds the 15-second budget DSH gives one index source. In that > case a **version-pinned** CDN URL is far faster — unpkg serves exact versions only, e.g. > `https://unpkg.com/dsh-plugin-catalog@/index.json`, with the version from `npm view dsh-plugin-catalog version` > (the catalog is rebuilt daily, so the version changes). ## License [MIT](LICENSE)