dsh-hot-reload 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,26 @@
1
+ # Changelog
2
+
3
+ All notable changes to `dsh-hot-reload` are documented here. This project
4
+ follows [semantic versioning](https://semver.org/).
5
+
6
+ ## 0.1.2
7
+
8
+ - Docs: add a **Compatibility** section (built/tested against dsh `0.1.0-rc.6`;
9
+ relies on cordis/loader internals, fails safe if they're absent).
10
+ - Docs: note that the plugin works in **any profile**, not just `web`.
11
+ - CI: publish workflow now also triggers on `v*` **tags** (in addition to pushes
12
+ to `main`), so releases can be cut either way.
13
+
14
+ ## 0.1.1
15
+
16
+ - Add Chinese README (`README.zh.md`) and ship it in the published package.
17
+
18
+ ## 0.1.0
19
+
20
+ - Initial release. Watches the profile's `pnpm-lock.yaml` and live-reloads an
21
+ upgraded plugin's module in place (invalidate + re-import + fiber swap,
22
+ mirroring `cordis-plugin-hmr` into `node_modules`).
23
+ - Optimistic with rollback: a failed reload (load error, or a sync/async `apply`
24
+ throw) keeps the old version live and logs that a manual restart is needed.
25
+ - `dsh.hotReload: false` opt-out; degrades to "restart needed" when loader
26
+ internals are unavailable.
package/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # dsh-hot-reload
2
2
 
3
+ English | [中文](README.zh.md)
4
+
3
5
  Live-reload upgraded [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (dsh) plugins **without restarting dsh**.
4
6
 
5
7
  dsh's built-in hot-reload (`cordis-plugin-hmr`) deliberately ignores
@@ -39,6 +41,18 @@ apply live:
39
41
  dsh plugin --profile web add some-plugin@newer # reloaded automatically
40
42
  ```
41
43
 
44
+ Works in **any profile** — swap `web` for whichever profile you use; it watches
45
+ the profile it's loaded into.
46
+
47
+ ## Compatibility
48
+
49
+ Built and tested against **dsh `0.1.0-rc.6`** (Node 22 / 24). It reaches into
50
+ cordis/loader internals shared with `cordis-plugin-hmr`
51
+ (`loader.internal.loadCache`, `registry.plugin`/`delete`, `fiber.entry`), so a
52
+ future dsh that changes those may require an update. It fails safe: if the
53
+ internals it needs are missing, it degrades to reporting "restart needed" rather
54
+ than breaking dsh.
55
+
42
56
  ## Opting out
43
57
 
44
58
  A plugin that knows it isn't safe to hot-reload can force the restart-needed
package/README.zh.md ADDED
@@ -0,0 +1,93 @@
1
+ # dsh-hot-reload
2
+
3
+ [English](README.md) | 中文
4
+
5
+ **无需重启 dsh** 即可热重载已升级的 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)(dsh)插件。
6
+
7
+ dsh 自带的热重载(`cordis-plugin-hmr`)刻意忽略 `node_modules`,所以升级一个已
8
+ 安装的插件(`dsh plugin add pkg@x`)通常要整体重启 `dsh` 才能生效。本插件补上
9
+ 这个缺口:它监听所在 profile 的 `pnpm-lock.yaml`,当一个**已加载**插件包的版本
10
+ 变化时,就地把运行中的插件换成新版。
11
+
12
+ ## 行为
13
+
14
+ 插件包升级时,对每个受影响的插件:
15
+
16
+ - **就地热重载**:使模块缓存失效、重新导入新代码、并就地重建插件 fiber。dsh、
17
+ 你的会话、以及其它所有插件都不受影响、继续运行。
18
+ - **若重载失败**:你保留的是**可用的旧版本**,绝不会留下一个失效的插件,同时
19
+ 记录一条“需要手动重启 `dsh`”的提示来加载新代码。两种情况都已处理:
20
+ - 新代码在**加载**阶段失败(错误的 import、语法错误)会在触及运行中的插件
21
+ **之前**被捕获——旧插件完全不受打扰;
22
+ - 新代码在**初始化**阶段失败(新的 `apply` 抛错,**同步或异步**)会被回滚——
23
+ 旧版本就地重新实例化。
24
+
25
+ 它**绝不会替你重启 dsh**——重启交给你(以及你的守护进程,如果有的话)。
26
+
27
+ ## 安装
28
+
29
+ ```sh
30
+ dsh plugin --profile web add dsh-hot-reload
31
+ ```
32
+
33
+ 然后重启一次 dsh(bundle 补丁层在启动时加载)。此后升级即实时生效:
34
+
35
+ ```sh
36
+ dsh plugin --profile web add some-plugin@newer # 自动热重载
37
+ ```
38
+
39
+ 适用于**任意 profile**——把 `web` 换成你用的 profile 即可;它监听自己被加载进的
40
+ 那个 profile。
41
+
42
+ ## 兼容性
43
+
44
+ 基于并测试于 **dsh `0.1.0-rc.6`**(Node 22 / 24)。它会用到与 `cordis-plugin-hmr`
45
+ 共享的 cordis/loader 内部(`loader.internal.loadCache`、`registry.plugin`/
46
+ `delete`、`fiber.entry`),因此未来若某个 dsh 版本改动了这些内部,可能需要更新
47
+ 本插件。它是失败安全的:一旦所需内部不可用,会退化为报告“需要重启”,而不会
48
+ 弄坏 dsh。
49
+
50
+ ## 退出热重载(opt-out)
51
+
52
+ 某个插件若知道自己不适合热重载,可在其**自己的** `package.json` 里声明,强制走
53
+ “需要重启”的路径(不做重载尝试):
54
+
55
+ ```json
56
+ { "dsh": { "hotReload": false } }
57
+ ```
58
+
59
+ ## 配置
60
+
61
+ 设置在所在 profile 的 `cordis.patch.yml` 里的 `hot-reload` 行上:
62
+
63
+ | 键 | 默认 | 含义 |
64
+ |---|---|---|
65
+ | `debounce` | `300` | lockfile 变化后等待多少毫秒再动作 |
66
+ | `profileDir` | 自动 | 要监听的 profile 目录绝对路径(省略时从 loader base URL 自动推断) |
67
+
68
+ ## 局限——务必阅读
69
+
70
+ 本插件是**乐观式**的,并非验证式。它尝试重载,且只在**抛出**错误时回退到
71
+ “需要重启”。它**无法**检测*静默*泄漏:
72
+
73
+ - 一个在 cordis 之外获取**裸资源**的插件——裸 `setInterval`、`net`/`http`
74
+ 服务器、`WebSocketServer`、`fs.watch`、`child_process`——**且没有用
75
+ `ctx.effect` 注册清理**,可能重载时不抛错,却把该资源遗留下来(游离的定时器、
76
+ 重复的监听器、孤立的 watcher)。这些会随每次升级累积,只能靠最终一次重启清除。
77
+ - cordis 会自动回收插件**通过 `ctx`** 注册的一切(`ctx.effect`、`ctx.on`、
78
+ `ctx.provide`、工具 schema、适配器),所以行为规范的插件都能干净地重载。风险
79
+ 仅限于绕过 `ctx` 的插件。拿不准时,让这类插件设 `dsh.hotReload: false`。
80
+ - 重载一个持有**活动连接**的插件(例如 WebSocket 桥接)会断开并重建这些连接;
81
+ 客户端需要重连。这是预期行为,不是错误。
82
+ - 重载路径依赖 cordis/loader 内部(`loader.internal.loadCache`、
83
+ `registry.plugin`/`delete`、`fiber.entry`)——与 `cordis-plugin-hmr` 用的是同
84
+ 一套。若这些内部不可用(既无 `--expose-internals`,也无
85
+ `node-addon-require-builtin` 原生插件),本插件会退化为对每次变化只报告
86
+ “需要重启”,而不做重载。
87
+
88
+ 范围说明:本插件处理的是**已加载插件的升级**。安装一个**全新**插件是另一回事
89
+ (把它的行加入 `cordis.patch.yml`,这个 dsh 本身已经会热应用)。
90
+
91
+ ## 许可证
92
+
93
+ [MIT](LICENSE) © Stuart Hu
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-hot-reload",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "type": "module",
5
5
  "description": "Live-reload upgraded DeepSeek Harness (dsh) plugins without restarting dsh — safe plugins are hot-reloaded in place; unsafe ones are flagged for a manual restart.",
6
6
  "keywords": [
@@ -35,6 +35,8 @@
35
35
  "lib",
36
36
  "cordis.patch.yml",
37
37
  "README.md",
38
+ "README.zh.md",
39
+ "CHANGELOG.md",
38
40
  "LICENSE"
39
41
  ],
40
42
  "dsh": {