HIT-HTML/dsh-ENHANCED1

dsh-enhanced

Everyday upgrades for DeepSeek Harness in one plugin: vendored multi-engine free web search (with self-hosted SearXNG support), persistent skills and MCP server management, auto-compact tuning, instance controls, and Matrix/Cyberpunk themes

包名
dsh-enhanced
版本
1.0.0
许可证
MIT
最近更新
2026年8月25日

安装

此插件尚未提供可验证的 bundle,或兼容性检查未通过。请先阅读仓库说明。 阅读完整 README ↗

dsh-enhanced

preview

One plugin that bundles the everyday upgrades DeepSeek Harness (DSH) lacks out of the box:

  • Free web search — a vendored multi-engine search provider (DuckDuckGo ×2, Bing, AnySearch, SearXNG, Mojeek-ready fallback chain + optional paid engines), configured from a Settings tab, with self-hosted-SearXNG support and live health checks.
  • Skills manager — install/edit/remove agent SKILL.md skills persistently. Installs accept a single skill or a folder OF skills (disk path or browser folder-picker alike), keep bundled scripts/ executable (browsers drop permission bits; shebang files are restored to 0755), and report per-skill results so one bad bundle never blocks the rest.
  • MCP server manager — manage @deepseek-ai/dsh-mcp-client rows across profiles.
  • Auto-compact tuner — clamp the context-compaction trigger below the harness default.
  • Instance controls — clean shutdown/restart of the GUI process via icon buttons beside Settings in the sidebar foot.
  • Themes — original ENHANCED theme (phosphor-green terminal look, digital-rain boot intro) and a Cyberpunk 2077 theme ported from the community theme.

Single host composition plugin (cordis.patch.yml row), single model tool surface (manage_skills_mcps), single browser card (Settings → Plugins). No telemetry, no external services beyond the search engines themselves.


Install

dsh plugin add https://github.com/HIT-HTML/dsh-ENHANCED   # or clone into a profile and add a composition row

The repo ships prebuilt dist/ and client.js, so no build step is needed to install. To develop, see Development.

Plugin row (usually written for you by dsh plugin add):

- id: dsh-enhanced
  name: dsh-enhanced
  config:
    mcpProfiles: ["default", "web"]   # whose cordis.patch.yml receives managed rows
    allowRestart: false               # opt-in for supervisor-assisted restarts

Architecture

Two halves, standard DSH plugin shape:

┌─ HOST (Node, src/*.ts → dist/) ─────────────────────────────┐
│ index.ts   composition root: registers the model tool,      │
│            browser RPC channel, settings anchor, boots the  │
│            vendored search engine                           │
│ shared.ts  paths, managed-block surgery, Env/Handler types  │
│ skills.ts  mcp.ts   compact.ts   instance.ts   search.ts    │
│            feature modules — each owns its actions end-to-end│
│ free-search-vendor.ts   vendored engine (see below)         │
└──────────────┬──────────────────────────────────────────────┘
               │ package-private JSON RPC (browser → host)
┌─ CLIENT (browser, client/** → client.js bundle) ────────────┐
│ core.js        draft/save pipeline, sections registry       │
│ main.js        boot, saved-theme activation                 │
│ sections/*     one card per feature (skills, mcp, compact,  │
│                search, theme)                               │
│ themes/*       matrix, cyberpunk2077 (+ boot intro)         │
└─────────────────────────────────────────────────────────────┘

Persistence is deliberately boring: every host feature writes marker-delimited "managed blocks" into /cordis.patch.yml (and ~/.dsh/skills/ for skills). No database, no state file — the user's config tree is the state, readable by eye:

# >>> dsh-enhanced:mcp >>>     …rows…      # >> dsh-enhanced:compact >>> …row…       # >> dsh-enhanced:search >>>  …row…       # .ts` exporting `ACTIONS` + `Handler`, two lines in `index.ts`, one section file under `client/sections/`. That's the whole integration story.

---

## Feature reference

| Module | Actions | Writes to |
|---|---|---|
| skills | `list_skills, read_skill, add_skill, edit_skill, remove_skill, install_skill, install_skill_files` | `~/.dsh/skills//SKILL.md` |
| mcp | `list_mcps, mcp_status, add_mcp, remove_mcp, enable_mcp, disable_mcp` | managed `:mcp:` block |
| compact | `compact_status, set_compact` | managed `:compact:` block |
| instance | `shutdown_instance, restart_instance` | process control only |
| search | `list_search, set_search` | managed `:search:` block |

Client-side, each feature is a *section* plugged into three registries in `core.js`:
`DRAFT_SHAPES` (form state), `DIRTY_CHECKS` (unsaved chip), `SAVE_STEPS` (replay on Save).
Sections self-fetch on expand and stage edits locally; Save replays steps in order and
a mid-batch failure keeps exactly the unapplied part staged.

Secrets (API keys) are **never echoed back**: `list_search` reports `hasKey.` booleans,
key inputs start blank meaning "unchanged", and only non-blank values are written.

---

## Search subsystem

### Provenance

The engine is **vendored** from [`dsh-free-search`](https://github.com/DDDMUC/dsh-free-search)
v0.4.12 (MIT, © DDDMUC) into `src/free-search-vendor.ts`. We vendor rather than depend because
upstream's peerDependencies aren't published to npm — fresh installs of the standalone plugin
can fail outright. Upstream fixes do **not** propagate automatically; re-port when adopting them.

Local adaptations vs upstream (all collision-safety or de-branding):

| What | Upstream | Here |
|---|---|---|
| settings namespace | `free-search` | `enhanced-free-search` |
| bridge prefix | `/api/dsh-free-search-settings` | `/api/dsh-enhanced-free-search` |
| search provider id | `ddg` | `enhanced-free` |
| settings UI section | installed its own card | removed — our Search tab owns config UX |
| self-update machinery | check-update + `pnpm add` upgrade routes | removed — a vendored copy must not reinstall upstream over itself |
| agent-visible strings | "Settings > Plugins > Free Search" | point at this plugin's Search section |

### Boot flow

profile cordis.patch.yml dsh-enhanced host boot :search: managed block ─┐ ├─► index.ts: readSearchConfig(profiles[0]) Settings→Search tab ────┘ │ ▼ ctx.inject(["web"], scope => freeSearch.apply(scope, cfg)) │ registers provider id "enhanced-free", agent tools, system-prompt section, bridge routes │ ▼ harness web_search / advanced_search route through it


Config is read once at boot — after saving in the tab, restart the profile to apply.
If the standalone `dsh-free-search` is also installed somewhere, nothing clashes:
distinct namespace/prefix/provider-id, and each registration is guarded.

### Engines and the fallback chain

Preferred engine = your Provider dropdown. On failure/empty results the chain walks on:

paid (only if keyed): exa → tavily → keenable → perplexity → deepseek-official free, always: bing → anysearch → ddg → ddg-lite → searxng


Time filtering (`advanced_search`) is honored by engines that support it and skips the rest.
Results are cached per query (LRU ~50, TTL ≤5 min, configurable).

### SearXNG instances (self-hosted path)

Public SearXNG instances rate-limit the JSON API to death; run your own:

```bash
mkdir -p ~/.searxng && cat > ~/.searxng/settings.yml  /tmp/lab-port.yml
dsh --profile lab --patch /tmp/lab-port.yml

Serves the workspace client live (cache-control: no-cache), so client edits show on refresh; host edits need a lab restart. Never point this at your main profile.

Adding an engine (search)

  1. src/free-search-vendor.ts: const X_URL, async function searchX(query, maxResults, options, signal) returning { sources: [{url,title?,snippet?}], truncated:false } — reuse fetchHtmlWithRetry, stripTags, uniqueSources.
  2. Add the id to FREE_ENGINES / ALL_ENGINES, the freeEngines chain array inside provider.search, and a case in runEngineTest.
  3. client/sections/search.js: one PROVIDER_META entry (free: true unless it needs a key).
  4. Smoke-test through the bridge: curl -X POST .../raw-search -d '{"engine":"x","query":"hi"}'.

Adding a feature module

Copy the shape of src/compact.ts (smallest full example): actions const, Handler switch, managed block via splitBlock/writeFile, guard-rails server-side. Then one handleX line + X_ACTIONS spread in index.ts, and a section file registering into the client registries.

Release checklist

  • npm run build && npm run selfcheck
  • Lab bench smoke: bridge query with preferred engine + one fallback
  • dist/ and client.js are committed artifacts here — make sure they're fresh
  • No machine-specific paths or secrets in tracked files (git grep -E "/Users/|sk-[A-Za-z0-9]")
  • Bump package.json version

Privacy & security notes

  • No telemetry. The only outbound traffic is the searches you (or your agent) run.
  • API keys are stored in the profile's cordis.patch.yml and never sent back to the browser (blank field = unchanged; hasKey booleans only).
  • The test bridge accepts loopback requests only (isLoopbackRequest guard) and redacts secrets.
  • Strings like EXA123 in tests are deliberate fixtures, not credentials.

License

MIT — see LICENSE. Contains code vendored from dsh-free-search (MIT, © DDDMUC) and theme work originating from the Cyberpunk 2077 community theme; both attributed in-file.