Development & Runtime

dsh-plugin-marketplace

AwesomeHou/dsh-plugin-marketplace · ★ 33

AwesomeHou

Plugin marketplace for DeepSeek Harness — live-syncs the GitHub dsh-plugin topic (1800+ repos) into a searchable, paginated settings tab with one-click install and agent tools (market_search / market_install).

License
MIT
Added
2026-08-16
Maintenance
active
Install kind
github
Manifest details
Manifest status
Declared
Manifest path
package.json#dsh
Manifest checked
2026-08-19
Lifecycle scripts
None found

Static manifest checks report declarations only; they are not compatibility or security review.

安装

dsh plugin --profile web add github:AwesomeHou/dsh-plugin-marketplace

GitHub 源码安装:首次需按提示配置 allowBuilds 构建授权后重试

For install and environment setup, plus plugin development tutorials, see DSH community docs ↗

README

Source README · body: en · Read Chinese README

Table of contents
  1. Features
  2. Install
  3. Manual install
  4. Let the agent install it
  5. How it is wired
  6. Development
  7. License

English | 中文

GitHub

A permanent DeepSeek Harness plugin that turns the GitHub dsh-plugin topic into a plugin marketplace — a tab inside 设置 → 插件, plus a pair of model tools so the agent itself can search and install plugins.

Marketplace screenshot Marketplace screenshot

The plugin marketplace: search, browse, one-click install, update.

Features

  • Paginated feed — the full topic is served page by page (default 50, max 100) from the GitHub Search API, with a "加载更多" (load more) button in the UI. No arbitrary 50-repo cap: total reflects the real total_count.
  • Search — keyword search runs through GitHub's own q, so it searches the whole topic rather than only loaded pages. Available both in the UI search box and via the market_search tool.
  • Agent tools (registered on Host via ctx.tools.register):
    • market_search(q?, page?, perPage?) — JSON list of topic repos (full name, stars, language, description, URL).
    • market_install(spec) — install into the web profile via dsh plugin --profile web add -w <spec>. Validates the spec against shell metacharacters before running; reports that a harness restart is required.
    • market_installed() — list the third-party plugins installed in the web profile: enabled state, installed/latest versions and whether an update is available (including this marketplace's own status). Built-ins are not listed.
    • market_update(name) — update one installed plugin to its latest version (restart required to take effect).
  • One-click install — every marketplace card has an 安装 (Install) button that POSTs /api/market/install and shows installing/installed/failed state.
  • Plugin updates (new-version hint) — every installed plugin is compared against its latest version (npm registry latest, or the version in the default-branch package.json for GitHub-hosted plugins). Cards get a 可更新 badge and an 更新 (Update) button via /api/market/update.
  • Built-in vs user-installed — packages in dsh.profile.bundles that come from the profile template are built-in (ship with the harness; cannot be disabled/uninstalled); packages later added to dependencies are user-installed. The 已安装 tab lists only user-installed (third-party) plugins — built-ins are not shown, and the page states this.
  • Disable / uninstall user-installed plugins — 停用 / 启用 (via /api/market/set-enabled) toggles the plugin in/out of dsh.profile.bundles (the dependency is kept); 卸载 (via /api/market/uninstall) runs dsh plugin --profile web remove <name> and drops it from the bundle layer list. Both need a harness restart.
  • Profile writes are serialized (batch uninstalls just work) — install, update, uninstall and disable/enable all read-modify-write the same profile package.json (and the same node_modules), so the host funnels every one of them through a single FIFO (onProfileWrite). Previously two concurrent 卸载 runs each read the old manifest and the last write restored the other plugin's dependency — which is why "uninstall several at once" removed only one. They now run one after the next and every one of the batch is really removed; a repeat/overlapping uninstall of the same plugin is an idempotent no-op, while a built-in is still refused with 内置插件不能卸载.
  • One button while an action runs — while a plugin is being acted on, its card keeps only that one button, relabelled 更新中… / 停用中… / 启用中… / 卸载中…, and hides the siblings instead of turning them into a generic "Processing…" button. A disabled plugin is tagged 已停用 (previously "已关闭").
  • Self-update check — the marketplace checks its own latest version (read from its GitHub repo's package.json). When a new version exists, a banner vX → vY · 立即更新 appears at the top of both the 插件市场 and 已安装 tabs.
  • Source disclosure — the 插件市场 tab states its source: the GitHub dsh-plugin topic (github.com/topics/dsh-plugin), synced live through the GitHub Search API.
  • Inside the Plugins settings — registers two settings.plugins.tab entries (market 插件市场, installed 已安装) beside the shipped "插件配置" (Plugin config) and "插件列表" (Plugin list) tabs.

Install

Manual install

dsh plugin --profile web add https://github.com/AwesomeHou/dsh-plugin-marketplace

Requires a harness restart to take effect.

Let the agent install it

Install this plugin for me: https://github.com/AwesomeHou/dsh-plugin-marketplace

How it is wired

Piece File Role
Bundle manifest package.json dsh.bundle.patch (host layer) + dsh.client (browser module)
Patch layer cordis.patch.yml Inserts the plugin's own host row into the Loader tree
Host half lib/index.js GitHub paginated sync + /api/market/list, /api/market/installed, /api/market/update, /api/market/set-enabled, /api/market/uninstall + market_search/market_install/market_installed/market_update tools
Client half lib/client.js __ModuleLoader__ bundle: 插件市场 / 已安装 settings tabs + search + load-more + one-click install + update / disable / enable / uninstall + self-update banner. UI copy lives in the MARKET_LOCALES dictionary (zh/en), resolved via ctx.locale

Data flows over the same-origin HTTP endpoints (/api/market/*) the Host half registers on ctx.webServer — permanent bundles have no harness/host.call sandbox RPC, so the browser half uses fetch.

Development

npm run check   # syntax-check both halves

License

MIT