DeepSeek Harness plugin

dsh-live-reload

One-click hot reload of the running DeepSeek Harness plugin composition without restarting the process.

Jump to install

Source facts

Repository
xuhurdern-beep/dsh-live-reload
Latest update
Aug 17, 2026
Category
Development & Runtime
GitHub stars
2
Format
bundle
Catalog evidence
Upstream dsh.bundle evidence
Evidence path
package.json#dsh.bundle
Checked against
0.1.0-rc.8
Upstream check date
2026-08-20

This evidence comes from the upstream catalog. This site has not installed, run, or security-reviewed the plugin.

Install

Start with a prompt that asks an agent to review the GitHub repository and source. Switch to the command if you want to install it yourself.

Copy this prompt into DSH, Codex, or another agent and ask it to review the GitHub repository and source first.

Do not install or run any commands yet. Read this plugin's GitHub repository, README, and relevant source code. Then answer the questions below clearly and directly so I can decide whether it fits my needs:

1. What is this plugin, and what problem does it solve?
2. Who is it for, and what are its typical use cases?
3. How is it used after installation? Include one minimal example.
4. What known limitations or privacy, security, compatibility, or maintenance risks does it have?
5. Give a clear recommendation: recommend, conditionally recommend, or do not recommend, with reasons.

Distinguish statements documented by the repository, inferences from source code, and unknowns. If evidence is insufficient, say so explicitly. Do not guess or simply repeat the README.

GitHub: https://github.com/xuhurdern-beep/dsh-live-reload
Plugin: dsh-live-reload
Author: xuhurdern-beep

Check the source files

Read the README and other files from this plugin directory before installing.

File explorer3 files
README.mdSource · read only

dsh-live-reload

One-click hot reload of the running DSH plugin composition — without restarting the process.

dsh-live-reload re-reads your profile's full plugin composition — every bundle layer (dsh.profile.bundles), the profile user layer (cordis.patch.yml), the home user layer ($DSH_HOME/cordis.patch.yml) and the launcher overlays (--patch, the agent-presets shipped-roots overlay, the telemetry switch) — and applies it live to the running tree through the root Include. The process, the web server and every open session stay up: the loader mounts new rows, config-updates changed rows and disposes removed rows transactionally, rolling back on failure. Only the rows that actually changed are touched.

> Today, installing a new plugin (e.g. via the plugin market) often ends with > "restart DeepSeek Harness to apply". This plugin is the general fix for that: a button in > Settings that hot-applies the whole composition, then reloads the page so new client > bundles land in the running browser — the host process itself never exits.

Features

  • One-click refresh — a "Plugin Refresh / 插件刷新" section in Settings.
  • Full recomposition — covers bundle layers (the part a normal boot freezes), user patch

layers, --patch overlays, the agent-presets shipped-roots overlay and the DSH_TELEMETRY_DISABLED switch; verified byte-faithful against the launcher's own dsh --profile <name> --dump-config (see scripts/validate-composition.mjs).

  • Safe by construction — reuses the exact transactional update path the built-in HMR

uses on every cordis.patch.yml save; unchanged rows are never restarted, failures roll back, a refresh is serialized and bounded by a timeout.

  • Result report — the button shows added / removed / updated rows and any activation

errors; a successful refresh then always reloads the page (no diff-based "did new client bundles appear" detection — the reload re-fetches the live boot manifest, which already carries any new package's client bundle, so a market hot-install lands every time). Failure details surface the whole cause chain (incl. AggregateError.errors), so a wrapped error like failed to rollback loader entry ...: never hides the real reason.

  • No process exit — the host keeps running; sessions replay their history from the

persisted log after the page reload (the web app's standard reload recovery).

  • Hot package updates (0.2.0) — every bundle is fingerprinted on disk (seeded at

boot); when a mounted package's files change in place (market reinstall/update), the refresh re-points its loader rows at a cache-busted entry URL, so the loader re-imports and runs the NEW code — no restart, and no "tool already registered" collision (the loader withdraws the old fiber's registrations before starting the new one). The refresh additionally evicts the package's cached modules from the Node ESM loadCache (entry AND relative dependencies — a ?dshr= on the entry alone cannot reach ./dep.js), so upgrades that changed non-entry files (e.g. a new export in lib/*.js) also load fresh.

  • Collision self-heal (0.2.0) — if a refresh still hits

tool "X" is already registered, the plugin identifies the offending package, force-busts its module cache and retries once — the collision heals itself without a restart (selfHealed in the result). This also covers the market's hot-mount residue: when a plugin was hot-installed (mkt-* rows in the market's runtime-only subtree) and the bundle layer later owns the same package, the refresh disposes the conflicting live mkt-* row (withdrawing its registrations) before re-applying the bundle-layer row.

Install

# from the repo checkout (development) or a published copy:
dsh plugin --profile web add github:<your-name>/dsh-live-reload

# or a local checkout (development iteration):
dsh plugin --profile web add link:/absolute/path/to/dsh-live-reload

The bundle layer activates on the next dsh web boot — one restart is required only to install the plugin itself. From then on, plugin installs/removals/config edits can be applied with the refresh button, no more restarts.

Usage

1. Open the Web GUI → Settings → Plugin Refresh / 插件刷新. 2. Click 一键刷新插件并重载页面 / Refresh Plugins & Reload. 3. On success the page reloads automatically after a short pause — new client bundles (e.g. a just-installed plugin's UI) land in the browser; the host process and all sessions stay up. On failure the error panel stays readable and no reload happens.

Power users can call the same endpoints directly:

curl -s http://127.0.0.1:3080/dsh-live-reload/status
curl -s -X POST -H 'origin: http://127.0.0.1:3080' http://127.0.0.1:3080/dsh-live-reload/refresh

How it works

Settings button ──POST──▶ /dsh-live-reload/refresh
                            │
                            ▼
              composeFresh(profileDir)          # re-read bundle + user + overlay layers
                            │
                            ▼
        root Include entry.update({ config: { …includeConfig, patches } })
                            │        # the same transactional call the user-patch HMR makes
                            ▼
        loader reconciles: mount new rows · config-update changed rows · dispose removed rows
                            │
                            ▼
        audit (every enabled row has a live fiber) + diff report
                            │
                            ▼
        success → the client reloads the page (host process stays up)

The composition code (composeFresh) mirrors the launcher's composeProfile/composeLive exactly, including the two boot-only overlays most reimplementations forget:

  • the agent-presets shipped-roots overlay (without it a refresh would drop the

installation's own preset root from the live roster), and

  • the telemetry switch (DSH_TELEMETRY_DISABLED).

Compatibility

  • DSH profiles booted by the dsh --profile launcher (web, headless, custom). A hand-built

tree without a profile directory is detected and reported.

  • Requires @deepseek-ai/dsh-app-boot at runtime — it resolves through the profile's

node_modules / $DSH_HOME/profiles/node_modules installation fallback (never declared as a dependency, same as the ecosystem market plugin).

  • No dsh.bundle-level version pinning. Verified on 0.1.0-rc.5 (the harness

that ships the fallback modules); other rc-era releases should behave the same way, but only rc.5 has actually been exercised.

  • Windows / macOS / Linux — pure Node ESM host, zero native deps.

Verification

dsh-live-reload was verified end-to-end on a real booted instance, isolated from the working one (own DSH_HOME, OS-assigned port, node_modules junctioned to the installation fallback):

  • GET /dsh-live-reload/status200, correct profile.
  • POST /dsh-live-reload/refresh200 {ok: true}, zero changes, repeated

refreshes stable (no churn).

  • Appending a new bundle to dsh.profile.bundles then refreshing →

added: ["<row>"], errors: [] — the row mounts live, audit clean.

  • Removing it then refreshing → removed: ["<row>"] — the row disposes live.
  • GET /plugins/dsh-live-reload/client.js200; the boot manifest

(window.__DSH_BOOT__) carries the dsh-live-reload client entry.

The composition logic is additionally cross-checked against the launcher's own dsh --profile <name> --dump-config output by node scripts/validate-composition.mjs <profile> (row-identical, including the agent-presets shipped-roots overlay and the telemetry switch).

The whole suite is scripted: npm test boots an isolated instance and runs status / idempotent refresh / hot-mount / hot-unmount / client dispatch / clientGraphChanged end-to-end, plus the boot-vs-fresh agent-presets audit (see scripts/e2e.mjs).

Known interactions

The built-in HMR watcher recomposes on every cordis.patch.yml save from the bundle set captured at boot. If you install a new bundle and hot-apply it with this plugin, a subsequent manual edit of cordis.patch.yml makes the built-in watcher re-apply the boot-time bundle set (the new bundle's rows drop out) — just click the refresh button again afterwards: it re-reads everything fresh and re-applies the full composition.

What still needs a restart

  • **Updating an already-installed package whose loader rows are otherwise

unchanged**: the refresh fingerprints every bundle on disk and cache-busts the rows of changed packages (0.2.0) — a reinstall/update whose rows get re-applied hot-loads the new code. A package whose loader row is identical before/after the update has nothing to re-apply, so the new code still needs a restart (the refresh reports it via updatedOnDisk).

  • Changing the web frontend shell itself or the dsh binary.
  • The very first activation of this plugin (after install).

Development

npm run build:client   # requires tsdown locally: pnpm add -D tsdown@^0.22.14 (or: npm i -D tsdown@^0.22.14)
npm run check          # node --check on both halves + shipped-artifact guards
npm test               # scripted e2e on an isolated instance (see scripts/e2e.mjs)
node scripts/validate-composition.mjs web   # compare recomposition vs launcher dump

The client bundle (client/client.js) is the shipped artifact — rebuild and commit it when you change src/client/index.js. tsdown is intentionally not a declared devDependency: client/client.js is committed, and a git/npm install of this package must not drag in a build toolchain.

Security

The refresh performs no shell execution and mutates only the in-memory loader tree. The POST route is same-origin gated (matching the ecosystem market). A failed refresh rolls back to the last good tree — it never leaves a half-applied composition.

License

MIT