tianyaZTY/dsh-hot-plugin-host
Runtime plugin loading for the Web UI: a watched hot directory installs/updates client-plugin bundles live on every open page, no restart. Includes a right-column subagent dashboard example.
Listed
1
Dev
Bundle verified
What it does
Runtime plugin loading for the Web UI: a watched hot directory installs/updates client-plugin bundles live on every open page, no restart. Includes a right-column subagent dashboard example.
Best for
- Local Web UI development where client-plugin bundles change frequently.
- Developers who need a UI widget or dashboard to update across open pages without repeated DSH restarts.
- Teams prototyping Cordis client plugins with the normal loader lifecycle.
Not ideal for
- Production or shared environments where the hot directory could contain untrusted content.
- Server-side plugins or bundles that need modules outside the client module table.
- Setups that cannot perform the one initial restart required to load the host plugin.
README
dsh-hot-plugin-host
Runtime plugin loading for DeepSeek Harness Web — no restarts.
The DSH loader tree is composed at boot, so adding a static client plugin (a UI panel, a widget, a dashboard) normally requires restarting dsh web. This plugin fixes that: it watches a hot directory and installs/updates client plugin bundles at runtime on every open page.
write a bundle → ~/.dsh/hot-plugins/<id>/client.js
↓ (host polls every 1.5s)
/ hot-plugins/list + SSE events + bundle serving
↓ (browser half)
fetch → __ModuleLoader__.load → loader.create (full cordis fiber lifecycle)
↓
the plugin goes live on every open page — no restart, no refresh
Updates work the same way (overwrite the file → invalidate + live refresh). Delete the directory → the plugin disappears on next page load.
Install
# from this repo
mkdir -p ~/.dsh/profiles/web/node_modules
ln -s "$PWD" ~/.dsh/profiles/web/node_modules/dsh-hot-plugin-host
# add "dsh-hot-plugin-host" to dsh.profile.bundles in
# ~/.dsh/profiles/web/package.json
Then restart dsh web once (the host itself is a boot plugin). From then on, every future plugin ships through the hot dir with zero restarts.
npm:
dsh-hot-plugin-host(once published)
Usage
Drop a bundle into the hot directory:
mkdir -p ~/.dsh/hot-plugins/my-widget
cp examples/demo-widget/client.js ~/.dsh/hot-plugins/my-widget/
# within ~1.5s it is live on every open page
A hot bundle is the same __ModuleLoader__.load format as a boot bundle:
window.__ModuleLoader__.load({
id: "my-widget", // must equal the directory name
factory: (require) => {
// require() only modules in the client table: react, react/jsx-runtime,
// @deepseek-ai/dsh-client-runtime/client, ...
const inject = ["sessions", "slots", "locale"];
function apply(ctx) { /* full plugin powers: ctx.slots.register(...) */ }
exports.apply = apply;
exports.inject = inject;
return module.exports;
}
});
- id:
[A-Za-z0-9@._-], single path segment, no/ - routes:
GET /hot-plugins/list,GET /hot-plugins/events(SSE),GET /hot-plugins/<id>/client.js - hot dir:
DSH_HOT_PLUGINSenv override, default~/.dsh/hot-plugins(auto-created)
Examples
| Example | Description |
|---|---|
packages/dsh-client-ui-subagent-dashboard |
Subagent dashboard in the right column: live status, expandable details, background jobs, one-click open of the child session transcript. Ships as its own npm package; also works as a hot bundle. |
examples/demo-widget |
Minimal self-contained hot bundle: a live status chip. |
Security
The hot directory is a trust boundary, equivalent to the boot bundles list (a hot plugin gets full client-side service access). Local development machines only — never point it at untrusted content.
How it works
-
Host half (
lib/index.js): registers/hot-pluginsroutes onctx.webServer(list / SSE / bundle), polls the hot dir (mtime+size → rev), broadcastschangeevents. -
Browser half (
lib/client.js): injectsloader; reconciles on connect (list), subscribes to SSE, fetches changed bundles, executes them via the standard module loader, then mounts them withloader.create— the exact mechanism the officialdsh-cordis-client-runneruses for dynamic packages, giving hot plugins the full fiber lifecycle (activation gating, effect cleanup, status projection).
Related
- dsh-market — the community plugin market UI inside DSH (browse/search/one-click install)
- awesome-dsh-plugin — the curated registry this project is listed in
MIT
Frequently Asked QuestionsFAQ
Use the verified command dsh plugin --profile default add github:tianyaZTY/dsh-hot-plugin-host in a DSH-enabled shell. The command resolves the public package metadata and keeps the plugin attached to the catalog identity shown on this page.
Compatibility follows the bundle and profile status shown above. If a profile is not detected, keep the plugin disabled there and check the repository documentation before enabling it in production.
The GitHub link and activity metadata are the source of truth for releases and maintenance. Revisit this page after a new release to confirm the catalog has observed the latest version.