DeepSeek Harness 插件

dsh-live-reload

One-click hot reload of the running DeepSeek Harness plugin composition without restarting the process.(英文原文)

跳到安装方式

来源信息

GitHub 仓库
xuhurdern-beep/dsh-live-reload
最近更新
2026年8月17日
分类
插件开发工具
GitHub stars
2
载体类型
bundle
目录证据
上游声明已找到 dsh.bundle
证据路径
package.json#dsh.bundle
核对版本
0.1.0-rc.8
上游核对日期
2026-08-20

该证据由上游目录提供。本站没有安装、运行或安全审核这个插件。

安装

默认先复制一段 Prompt,让 Agent 读 GitHub 仓库和源码;需要自己装时再切到命令。

复制这段 Prompt,发给 DSH、Codex 或其他 Agent,让它先读 GitHub 仓库和源码。

请先不要安装或执行任何命令。阅读这个插件的 GitHub 仓库、README 和关键源码,然后用清楚、直接的方式回答以下问题,帮助我判断它是否适合我的需求:

1. 这个插件是什么,解决什么问题;
2. 适合哪些用户和典型使用场景;
3. 安装后如何使用,并给出一个最小使用示例;
4. 有哪些已知限制,以及隐私、安全、兼容性或维护风险;
5. 给出“推荐 / 有条件推荐 / 不推荐”的明确建议和理由。

请区分仓库明确说明、根据源码推断和未知信息。证据不足时请明确说明,不要猜测或照抄 README。

GitHub:https://github.com/xuhurdern-beep/dsh-live-reload
插件名:dsh-live-reload
作者:xuhurdern-beep

检查来源文件

安装前先看这个插件目录里的 README 和其他文件。

文件资源管理器3 个文件
README.md来源说明 · 只读预览

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