全部插件

DSH / BUNDLE / CLIENT-UI

dsh-hot-reload

v0.2.4stuarthu / dsh-hot-reload006d91589e

可安装组合包UI 与客户端插件社区 · Topic 自动分析Web UI

概览

dsh-hot-reload

Live-reload upgraded DeepSeek Harness (dsh) plugins without restarting dsh — the running plugin is swapped in place, and a reload that fails rolls back to the working old version and asks for a manual restart.

README / ZH

插件文档

目录摘要

Live-reload upgraded DeepSeek Harness (dsh) plugins without restarting dsh — the running plugin is swapped in place, and a reload that fails rolls back to the working old version and asks for a manual restart.

dsh.pub 核对固定版本的组合包契约、运行时事实与分发语义;完整 README 请查看源仓库。

在 GitHub 阅读完整 README

LIMITATIONS

已知限制

This plugin is **optimistic**, not verified. It attempts the reload and falls back to "restart needed" only when something **throws** (or when there is no live fiber to swap). It does **not** detect *silent* leaks: - A plugin that acquires a **raw resource outside cordis** — a bare `setInterval`, a `net`/`http` server, a `WebSocketServer`, an `fs.watch`, a `child_process` — **without a `ctx.effect` disposer** can reload without throwing yet leave that resource dangling (a stray timer, a duplicate listener, an orphaned watcher). These accumulate across upgrades and are cleared only by an eventual restart. - Cordis auto-unwinds everything a plugin registers **through `ctx`** (`ctx.effect`, `ctx.on`, `ctx.provide`, tool schemas, adapters), so well-behaved plugins reload cleanly. The risk is limited to plugins that bypass `ctx`. If in doubt, have such a plugin set `dsh.hotReload: false`. - Reloading a plugin that holds **live connections** (e.g. a WebSocket bridge) drops and re-establishes them; clients must reconnect. That's expected, not an error. - The reload path relies on the cordis/loader internals listed under [Compatibility](#compatibility). If they are unavailable (no `--expose-internals` and no `node-addon-require-builtin` addon), the plugin degrades to reporting "restart needed" for every change instead of reloading. - The lockfile is only the **trigger**. Version numbers are read from each package's installed `package.json`, because that is the only file that says what an import would really get. On pnpm 11 (measured on 11.21.0) the files on disk are written **first** and the lockfile **last**, so by the time this plugin acts, the versions it reads have settled. But nothing here *checks* that. If some future pnpm wrote the lockfile first, a check could read the old version, skip it, and never look again — the lockfile is the only thing watched, so that upgrade would be missed **silently**, with no message, until you install another version or restart dsh. The `debounce` setting does not help: the gap measured 2.5–4 seconds, far longer than any sane debounce. - The message channel (`GET /dsh-hot-reload/events`) has **no password check**, the same as dsh's own `/plugins/events`. It sends plugin names and version numbers. dsh already shows those through its plugin list, so this adds no new secret. But if you bind dsh to `0.0.0.0`, count it as one more address that anyone on your network can open. - A plugin that loads **after** `dsh-hot-reload` in the bundle order is reloaded once — to its current version — on the first lockfile write after boot, even when that write was for an unrelated package. Until this plugin has tracked the package across one cycle, it cannot tell whether the running code is the old or the current version, so it reloads rather than adopting a version that may never have run. For an HMR-safe plugin this is a harmless single redundant reload. - The state file is **required**. The plugin writes its tracked state to `profileDir/.dsh-hot-reload-state.json`. If that file cannot be written — for example because the profile directory is read-only — the plugin refuses to start (it throws) rather than running with in-memory-only state. Scope note: this handles **upgrades of already-loaded plugins**. Installing a *brand-new* plugin is a separate concern (adding its row to `cordis.patch.yml`, which dsh already hot-applies).