dsh-plugin-directory
其他 活跃维护

dsh-plugin-directory

dingzhenyao/dsh-plugin-directory

Web GUI插件,提供带统计维度的可浏览可搜索GitHub插件目录,支持CDN热更新、README校验安装与实时搜索,方便开发者快速找到所需插件。

3
Stars 标星
0
Forks 分支
3
Watchers 关注
0
Open Issues
TypeScript
主要语言
None
开源协议
3.5 MB
仓库大小
1 个月前
最后推送
一键安装扩展 / 插件指令
dsh plugin --profile web add github:dingzhenyao/dsh-plugin-directory
git clone https://github.com/dingzhenyao/dsh-plugin-directory.git
git clone git@github.com:dingzhenyao/dsh-plugin-directory.git
README.md main

dsh-plugin-directory

A plugin directory for the DeepSeek Harness (DSH) Web GUI. It renders a
Plugin directory tab inside Settings → Plugins that lets you browse,
search, filter, and compare GitHub repositories tagged with the
dsh-plugin topic — including each
plugin's install command, function category, install form, language, license,
stars, and a quality score.

中文说明见 README.zh.md。

Install

This plugin is itself a DSH plugin. Install it with the dsh CLI:

npm

dsh plugin add dsh-plugin-directory

git (when published under a GitHub org/user)

dsh plugin add github:dingzhenyao/dsh-plugin-directory

manual / local checkout

dsh plugin --profile <profile-name> add ./dsh-plugin-directory

After installation, open the DSH Web GUI and go to Settings → Plugins → 插件目录
(Plugin directory)
.

Compatibility

The plugin works with DeepSeek Harness 0.1.0-rc.5 (source checkout) and
0.1.0-rc.6 (npm). Its client peer dependencies accept >=0.1.0-rc.5 <0.2.0,
so both a local pnpm dsh checkout and an npm-installed dsh satisfy them.

Usage

The tab is a client-side directory over a snapshot of the dsh-plugin topic.
Repos are included when their README documents a dsh plugin command, they
carry the dsh-plugin topic, or their name/description mentions dsh-plugin —
the repo name itself does not need to contain "dsh". Candidates are ranked
by stars so real plugins outrank list/boilerplate repos:

  • Search — filter by plugin name, owner, or description; the query also
    triggers a live GitHub search for the latest matching repos (see below).
  • Category multi-select — combine any number of function categories
    (tool, skill, memory, vision, UI skin, MCP, orchestration, CLI/TUI, web,
    agent, other).
  • Install-form filter — restrict to bundle / repository / client / unknown.
  • Group-by dimension — group cards by function category, install form,
    language, or star bucket (default: no grouping).
  • Sort — by quality score, stars, or most recent update (default: stars).
  • Statistics dashboard — totals and breakdowns by category, install form,
    language, and star bucket.
  • One-click install — a card's Install button copies the plugin's
    install command, shown only when the plugin's own README documents a real
    dsh install command
    (see the extraction policy below).
  • My plugins — a personal management panel below the directory. Clicking
    Install records the plugin, and you can also add plugins manually (the
    source repository owner/repo is required) and remove or refresh existing
    entries. The list is stored in the browser's localStorage under
    dsh-plugin-directory:installed (see the note below).
  • Refresh — a manual refresh button re-pulls the latest snapshot from the
    CDN.

Install-method extraction policy

Every listed plugin carries an install field describing how to install it.
It is derived in priority order:

  1. Plugin's own README — the first real install invocation found in the
    README becomes the command, with the source line kept as a snippet. The
    scanner accepts dsh plugin add <target>,
    dsh plugin --profile <name> add <target>,
    pnpm dsh plugin [--profile <name>] add <target>, and a bare
    .dsh-plugin reference (github:<owner>/<repo>#<ref>&path:/.dsh-plugin).
    The --profile flag is preserved when present. Prose mentions without a
    concrete target are ignored.
  2. package.json signals — when the README has no install command but the
    plugin's manifest declares dsh.client or dsh.bundle, the npm package
    name is used: dsh plugin add <package-name>.
  3. .dsh-plugin directory — a repository plugin (no client/bundle
    manifest) is installed from the repo: dsh plugin add github:<owner>/<repo>&path:/.dsh-plugin.
  4. Fallback — when nothing above applies: dsh plugin add github:<owner>/<repo>.

The Install button is shown only for step 1 — when the plugin's own
README actually documents a dsh install command. Derived commands (steps
2–4) are recorded on the entry for future use but never surface a button, so
a repository whose README does not explain how to install it is never given a
guessed install button.

Data sync

  • data/plugins.json and data/meta.json are regenerated by the
    sync-data GitHub Actions workflow every 6 hours
    (cron 0 */6 * * *), fetching repos whose README documents a dsh plugin
    command, that carry the dsh-plugin topic, or that mention dsh-plugin in
    name/description (a repo name need not contain "dsh"), ranked by stars, and
    committing the resulting snapshot back to the default branch.
  • pnpm sync runs the same pipeline manually (deep-inspection results are
    cached in data/.inspect-cache.json and reused while a repo's pushed_at
    is unchanged).
  • data/overrides.json lets humans correct the keyword-based category
    classification, keyed by owner/repo.
  • The snapshot is bundled into the client as an offline fallback, and the tab
    refreshes it from a CDN at runtime (see below).

Runtime data refresh & live search

  • CDN refresh — on open, the tab fetches the latest snapshot from
    GitHub raw (https://raw.githubusercontent.com/dingzhenyao/dsh-plugin-directory/main/data);
    if it succeeds (and is no older than the bundled snapshot) it replaces the
    bundled snapshot and shows the last sync date, and if it fails (offline) it
    silently keeps the bundled snapshot. The owner (dingzhenyao) is the GitHub
    account hosting the dsh-plugin-directory repository — a single fixed value
    baked in at build time, shared by every installer (not per-installer).
    raw.githubusercontent.com follows the branch within minutes and serves
    files with Access-Control-Allow-Origin: *.
  • Live search — typing a query also queries the GitHub Search API for
    topic:dsh-plugin repositories matching the query (debounced, 20 results),
    and appends them as a Live results section (deduped against the
    snapshot). Live results have no README inspection, so they show no install
    button. On rate-limit / failure the tab degrades to local results with a
    notice.

My plugins (host-file management)

The My plugins panel records the plugins you manage through this
directory. It is backed by a host-side data file at
$DSH_HOME/storages/dsh-plugin-directory/installed.json, written through a
Typert Remote (ctx.remote.pluginManager.*) from the browser:

  • Clicking a card's Install button adds the plugin (recorded with the
    github:<owner>/<repo> source and method search).
  • Add accepts a manual source repository — owner/repo or
    github:owner/repo — and rejects anything that is not a valid
    owner/repo (method manual). The display name is the repo basename.
  • Update refreshes an entry's timestamp (reinstall); Delete removes
    it.
  • Sync status reads the harness's real Loader inventory (the built-in
    read-only pluginInventory Remote) and shows a per-entry badge: installed
    (with enabled/failed/loading refinements), disabled, not
    installed
    , or unknown (inventory unavailable). Matching is by the
    Loader moduleName against the ledger id/source, with a unique-basename
    fallback so an npm install of the same project still lines up with a
    recorded git source. The inventory is re-read automatically every 30 seconds
    (and on demand via the Sync status button).

The ledger is bookkeeping only: it records which plugins you triggered an
install for (plus manual additions), and it does not actually run
dsh plugin add/remove or read your exact install state back into the file —
the real install state is shown live via the inventory sync, not persisted.

How the Remote works

The host exports PluginManagerGateway (a TypertRemoteService subclass with
@Remote('list' | 'add' | 'delete' | 'update') methods). The host gateway
discovers it through its SRC fallback (resolveSrcDescriptor) — no generated
./typert manifest is required. The client half hand-writes the matching
TYPERT_REMOTE contribution (src/client/remote.ts) with strict zod
codecs (the client gateway rejects src-json), mounts it via
ctx.remote.$mount(...), and the tab calls ctx.remote.pluginManager.*.
The real install status comes from the harness's own read-only
ctx.remote.pluginInventory Remote (mounted by @deepseek-ai/dsh-api-remotes).

The browser bundle needs @deepseek-ai/dsh-api-remotes injected (it provides
ctx.remote), and the host build lowers the standard @Remote decorator via a
tsdown transform (ts.transpileModule) so the method markers register at
runtime.

The validation helpers (isSourceRepo / normalizeSource) are shared between
the host (src/data/installed.ts) and client (src/data/installed-types.ts).

Development

pnpm install
pnpm build       # tsdown → lib/index.js (host half) + lib/client.js (browser half)
pnpm test        # vitest
pnpm sync        # refresh data/ from the GitHub dsh-plugin topic
pnpm typecheck   # tsc --noEmit

In the DSH file sandbox, vite's Windows realpath probe spawns a suppressed
child process, so run tests through the shim:

NODE_OPTIONS=--require=./scripts/vitest-sandbox.cjs pnpm test

Known limitations

  • Category label language — fixed copy (tab name, buttons, placeholders)
    follows the active UI language immediately, but category/install-form label
    dictionaries are read when the tab page opens: after switching the UI
    language, reopen the tab for the updated labels.
  • "My plugins" is bookkeeping, status is live — the panel stores which
    plugins you triggered an install for (and manual additions) in the host data
    file, but does not write the harness's real install state back; the
    per-entry installed/disabled/failed badge is read live from the Loader
    inventory via Sync status, so an install performed outside this
    directory only shows up if its moduleName matches a recorded entry.
  • CDN cache delay — raw.githubusercontent.com serves the branch with a
    ~5-minute cache, so a fresh CI commit reaches the CDN refresh within minutes
    (and a stale edge cache is rejected in favor of the bundled snapshot); live
    search covers the gap for the very newest repos.
  • Unauthenticated search quota — the live-search feature queries GitHub's
    search API from the browser (unauthenticated, 10 requests/minute); it is
    debounced and degrades to local results on rate-limit. The sync pipeline
    uses GITHUB_TOKEN in CI (see .github/workflows/sync.yml).
  • CDN requires the repo to be published — the CDN refresh and git-install
    line point at github.com/dingzhenyao/dsh-plugin-directory; until that
    repository exists (pushed to GitHub), the tab silently falls back to the
    bundled snapshot. Change src/client/data.ts (CDN_BASE) if the repo moves.

License

MIT