Skip to content

dsh-research-panel

Verified

dsh-research-panel · v0.1.1 · MIT · Web UI

Research tab for the DSH Web session page: a read-only panorama of installed agent skills — trigger commands (/skill) plus plain-language purpose notes, so users never have to memorize the skill corpus.

Install

dsh plugin add dsh-research-panel

Confirm the layer applied with dsh --profile default --dump-config — see the install guide.

Source

Published to npm without a public repository. Inspect the package contents before installing.

Tags

Readme

dsh-research-panel

A DeepSeek Harness web bundle that adds a Research tab to the session view switcher (right of 会话 / 轨迹).

It answers one question: what skills are actually installed right now? For every skill found it shows the trigger command (/name, click to copy) and a plain-language purpose, so the corpus does not have to be memorized. A curated Chinese overlay (dsh/curated.json) sits on top of the live scan, with the original SKILL.md description as the fallback — the UI records which one is showing.

How it works

  • The host half scans every SKILL.md under the skill roots in precedence order (~/.agents/skills, then ~/.claude/skills) and merges the curated overlay.

  • It mounts one exact route on the authenticated shared /api channel:

    POST /api/research-panel/skills  →  { ok: true, value: { features, workflows, updated, all } }
    
  • The browser half calls that route with plain fetch, resolving the URL against document.baseURI so a deployment prefix survives.

Compatibility

Built for dsh 0.2.0-rc.2. Declared peers: @deepseek-ai/dsh-client-connection and @deepseek-ai/dsh-client-ui-conversation at ^0.2.0-rc.2.

Why 0.1.0 broke on 0.2.0-rc.2 (and why nothing said so)

0.1.0 mounted its host endpoint with ctx.connection.rpc.handle('/research-panel', handler). That call registers its physical route as owner.effect(() => owner.webServer.register(route)); the effect's own fiber carries no injects, so the owner.webServer read throws

Error: cannot get property "webServer" without inject

from any non-root caller. The host half therefore loaded cleanly, registered nothing, and the browser's POST /research-panel/skills fell through to the static SPA handler — HTTP 405, which is what the tab reported as 加载失败:transport failure for /research-panel/skills: HTTP 405.

Two independent reasons this stayed silent:

  1. The plugin declared no peerDependencies, so dsh's 0.2.0 peerDependency gate had nothing to compare and never flagged the bundle. 0.1.1 declares both services at ^0.2.0-rc.2 so the next drift is caught at startup instead of at click time.
  2. rpc.handle is still exported and documented, but no package in the dsh tree calls it any more; the shared channel's single rpc.intercept slot belongs to dsh-api-gateway.

0.1.1 uses ctx.connection.fetch.register() — the documented extension point for "exact Fetch routes that cannot use JSON Remote invocation" on the shared /api channel, already behind the Host/Origin fence and browser authentication. It never touches owner.webServer, so it works from any plugin context. dsh-api-session-controller (GET|HEAD /api/file), dsh-client-file-upload, dsh-client-ui-deliverables and dsh-session-log-export all mount their routes this way.

Install

dsh plugin --profile web add dsh-research-panel
# restart dsh web to activate the tab

User data ($DSH_HOME settings, credentials, sessions) is never touched.

Structure

dsh/index.mjs     host half — SKILL.md scan, curated overlay, /api route
dsh/client.js     browser half — the Research tab (conversation.view, id "research")
dsh/curated.json  curated Chinese descriptions and workflow sequences
cordis.patch.yml  dsh.bundle.patch — inserts the research-panel row
test/host-smoke.mjs  standalone smoke test for the pure host functions

License

MIT