概览
dsh-hot-reload
README / ZH
插件文档
目录摘要
dsh.pub 核对固定版本的组合包契约、运行时事实与分发语义;完整 README 请查看源仓库。
在 GitHub 阅读完整 READMELIMITATIONS
已知限制
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).
