dsh-hot-reload 0.2.2 → 0.2.3
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 +21 -0
- package/README-zh.md +10 -3
- package/README.md +13 -4
- package/lib/index.js +32 -12
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,27 @@
|
|
|
3
3
|
All notable changes to `dsh-hot-reload` are documented here. This project
|
|
4
4
|
follows [semantic versioning](https://semver.org/).
|
|
5
5
|
|
|
6
|
+
## 0.2.3
|
|
7
|
+
|
|
8
|
+
A plugin that loads after `dsh-hot-reload` in the bundle order is now reloaded
|
|
9
|
+
when it is upgraded, and every reload outcome — not just successes — reaches the
|
|
10
|
+
terminal. Config and API unchanged.
|
|
11
|
+
|
|
12
|
+
**Fixes**
|
|
13
|
+
|
|
14
|
+
- **A plugin loaded after this one now hot-reloads when upgraded.** A first-seen
|
|
15
|
+
package used to be adopted at face value whatever its version, so a plugin that
|
|
16
|
+
appears later in the bundle order (for example `dsh-crew`) kept running old
|
|
17
|
+
code when it had already been upgraded before this plugin's first cycle — the
|
|
18
|
+
change was silently missed. A first-seen package that has a live fiber is now
|
|
19
|
+
reloaded instead of adopted; a first-seen package with no live fiber is still
|
|
20
|
+
adopted, because there is nothing running to replace.
|
|
21
|
+
- **Every outcome now reaches the terminal.** `report()` used to write its stderr
|
|
22
|
+
line only for a successful reload. A failed or stale reload was then visible
|
|
23
|
+
only as a transient pop-up and a log line dsh never prints, so the "restart
|
|
24
|
+
dsh" instruction never reached anyone watching the terminal. stderr is now
|
|
25
|
+
written for every outcome — reloaded, failed, and stale.
|
|
26
|
+
|
|
6
27
|
## 0.2.2
|
|
7
28
|
|
|
8
29
|
Reloads now re-import a plugin's whole package, not just its entry module.
|
package/README-zh.md
CHANGED
|
@@ -42,7 +42,7 @@ dsh 自带的热重载(`cordis-plugin-hmr`)刻意忽略 `node_modules`,所
|
|
|
42
42
|
插件会把每个结果写进 dsh 的日志。但 dsh 不会把日志打印到你的终端,所以这些内容
|
|
43
43
|
很容易被忽略。另有两个地方会告诉你发生了什么。
|
|
44
44
|
|
|
45
|
-
**1.
|
|
45
|
+
**1. 每种结果,在你的终端里输出一行。** 任意 profile 都有:
|
|
46
46
|
|
|
47
47
|
```
|
|
48
48
|
dsh-hot-reload: hot-reloaded some-plugin@1.2.0 (1 module(s))
|
|
@@ -75,8 +75,9 @@ web 那一部分只在运行 web 服务器的 profile 中加载,并通过
|
|
|
75
75
|
|
|
76
76
|
### 如果你想在终端里看到全部内容
|
|
77
77
|
|
|
78
|
-
|
|
79
|
-
dsh
|
|
78
|
+
上面那一行覆盖每一种重载结果——成功、失败和 stale(未尝试、旧代码仍在运行)。若想
|
|
79
|
+
看到本插件写进日志的其它内容(它的警告和诊断信息),请把 dsh 的控制台日志插件加进
|
|
80
|
+
你的 profile。它是一个独立的包:
|
|
80
81
|
|
|
81
82
|
```sh
|
|
82
83
|
dsh plugin --profile web add @deepseek-ai/cordis-plugin-logger-console
|
|
@@ -192,6 +193,12 @@ web 应用里的提示(且仅这一部分)还用到:
|
|
|
192
193
|
这些内容,所以并没有多暴露什么秘密。但如果你把 dsh 绑定到 `0.0.0.0`,请把它
|
|
193
194
|
算作局域网里任何人都能打开的又一个地址。
|
|
194
195
|
|
|
196
|
+
- 在 bundle 顺序里排在 `dsh-hot-reload` **之后**加载的插件,会在启动后的第一次
|
|
197
|
+
lockfile 写入时被重载一次——重载到它当前的版本——即使那次写入针对的是另一个
|
|
198
|
+
包。在本插件跨过一轮循环、跟踪到该包之前,它无法分辨运行中的代码是旧版还是当前
|
|
199
|
+
版本,所以它选择重载,而不是采纳一个可能从未运行过的版本。对于 HMR 安全的插件,
|
|
200
|
+
这只是无害的单次多余重载。
|
|
201
|
+
|
|
195
202
|
范围说明:本插件处理的是**已加载插件的升级**。安装一个**全新**插件是另一回事
|
|
196
203
|
(把它的行加入 `cordis.patch.yml`,这个 dsh 本身已经会热应用)。
|
|
197
204
|
|
package/README.md
CHANGED
|
@@ -50,7 +50,7 @@ The plugin writes every result to dsh's log. But dsh does not print its log to
|
|
|
50
50
|
your terminal, so those lines are easy to miss. Two extra places show you what
|
|
51
51
|
happened.
|
|
52
52
|
|
|
53
|
-
**1. One line in your terminal, for
|
|
53
|
+
**1. One line in your terminal, for every outcome.** You get this in
|
|
54
54
|
every profile:
|
|
55
55
|
|
|
56
56
|
```
|
|
@@ -88,9 +88,10 @@ reload the page to start again.
|
|
|
88
88
|
|
|
89
89
|
### If you want every line in your terminal
|
|
90
90
|
|
|
91
|
-
The terminal line above
|
|
92
|
-
|
|
93
|
-
profile. It is a separate
|
|
91
|
+
The terminal line above covers every reload outcome — reloaded, failed, and
|
|
92
|
+
stale (not attempted — the old code is still running). To see everything else this plugin writes to the log (its warnings and
|
|
93
|
+
diagnostics), add dsh's console logger to your profile. It is a separate
|
|
94
|
+
package:
|
|
94
95
|
|
|
95
96
|
```sh
|
|
96
97
|
dsh plugin --profile web add @deepseek-ai/cordis-plugin-logger-console
|
|
@@ -221,6 +222,14 @@ live fiber to swap). It does **not** detect *silent* leaks:
|
|
|
221
222
|
secret. But if you bind dsh to `0.0.0.0`, count it as one more address that
|
|
222
223
|
anyone on your network can open.
|
|
223
224
|
|
|
225
|
+
- A plugin that loads **after** `dsh-hot-reload` in the bundle order is reloaded
|
|
226
|
+
once — to its current version — on the first lockfile write after boot, even
|
|
227
|
+
when that write was for an unrelated package. Until this plugin has tracked the
|
|
228
|
+
package across one cycle, it cannot tell whether the running code is the old or
|
|
229
|
+
the current version, so it reloads rather than adopting a version that may
|
|
230
|
+
never have run. For an HMR-safe plugin this is a harmless single redundant
|
|
231
|
+
reload.
|
|
232
|
+
|
|
224
233
|
Scope note: this handles **upgrades of already-loaded plugins**. Installing a
|
|
225
234
|
*brand-new* plugin is a separate concern (adding its row to `cordis.patch.yml`,
|
|
226
235
|
which dsh already hot-applies).
|
package/lib/index.js
CHANGED
|
@@ -18,9 +18,9 @@
|
|
|
18
18
|
// row with no fiber attached yet is reported and left for a later change.
|
|
19
19
|
//
|
|
20
20
|
// Outcomes are announced on two surfaces besides ctx.logger — one stderr line
|
|
21
|
-
// per
|
|
22
|
-
// turns into a transient toast. Both are additive and
|
|
23
|
-
// "notification surfaces" section in apply().
|
|
21
|
+
// per outcome (reloaded, failed, or stale), and an SSE channel the browser half
|
|
22
|
+
// (lib/client.js) turns into a transient toast. Both are additive and
|
|
23
|
+
// best-effort; see the "notification surfaces" section in apply().
|
|
24
24
|
//
|
|
25
25
|
// NOTE: the reload path uses cordis/loader internals (loader.internal.loadCache,
|
|
26
26
|
// registry.plugin/delete, fiber.entry) — the same ones HMR uses. If a future
|
|
@@ -87,10 +87,11 @@ export function apply(ctx, config = {}) {
|
|
|
87
87
|
// and neither may throw into a reload cycle: a broken notification must never
|
|
88
88
|
// turn a working reload into a failed one.
|
|
89
89
|
//
|
|
90
|
-
// - stderr,
|
|
90
|
+
// - stderr, every cycle outcome. cordis's logger fans messages out to
|
|
91
91
|
// registered exporters, and the dsh host process registers none (only the
|
|
92
92
|
// browser shell does), so nothing this plugin logs reaches the terminal dsh
|
|
93
|
-
// runs in. One line per
|
|
93
|
+
// runs in. One line per outcome — reloaded, failed, or stale — is the
|
|
94
|
+
// profile-independent baseline.
|
|
94
95
|
// - an SSE channel the web half subscribes to (lib/client.js) and renders as
|
|
95
96
|
// a transient toast. Registered only when a webServer service exists, so a
|
|
96
97
|
// profile without one — tui — behaves exactly as it does today.
|
|
@@ -112,17 +113,23 @@ export function apply(ctx, config = {}) {
|
|
|
112
113
|
*
|
|
113
114
|
* `kind` is "reloaded" (it worked), "failed" (attempted and rolled back), or
|
|
114
115
|
* "stale" (not attempted; the old code is still running). It selects the log
|
|
115
|
-
* level and the browser's icon
|
|
116
|
-
*
|
|
116
|
+
* level and the browser's icon. Every kind also reaches stderr — successes
|
|
117
|
+
* and failures alike — because the dsh host registers no cordis logger
|
|
118
|
+
* exporter, so the log.* line above never reaches the terminal on its own.
|
|
119
|
+
* Callers pass the bare message — every surface adds its own prefix. */
|
|
117
120
|
function report(kind, message) {
|
|
118
121
|
if (kind === "reloaded") {
|
|
119
122
|
log.info?.(`dsh-hot-reload: ${message}`);
|
|
120
|
-
try {
|
|
121
|
-
process.stderr.write(`dsh-hot-reload: ${message}\n`);
|
|
122
|
-
} catch {}
|
|
123
123
|
} else {
|
|
124
124
|
log.warn?.(`dsh-hot-reload: ${message}`);
|
|
125
125
|
}
|
|
126
|
+
// One durable, profile-independent line per outcome, written for every kind.
|
|
127
|
+
// A failed/stale reload used to be visible only as a transient toast plus an
|
|
128
|
+
// invisible log line (dsh exports no logger), so "restart needed" never
|
|
129
|
+
// reached anyone looking at the terminal dsh runs in.
|
|
130
|
+
try {
|
|
131
|
+
process.stderr.write(`dsh-hot-reload: ${message}\n`);
|
|
132
|
+
} catch {}
|
|
126
133
|
if (!connections.size) return;
|
|
127
134
|
const line = `data: ${JSON.stringify({ type: "notice", kind, text: message })}\n\n`;
|
|
128
135
|
for (const res of connections) {
|
|
@@ -511,8 +518,21 @@ export function apply(ctx, config = {}) {
|
|
|
511
518
|
continue;
|
|
512
519
|
}
|
|
513
520
|
if (!(pkg in versions)) {
|
|
514
|
-
|
|
515
|
-
|
|
521
|
+
// A package our boot snapshot never saw. Two cases:
|
|
522
|
+
// - no live fiber: nothing is running yet (mid-import, or only disabled
|
|
523
|
+
// rows), so there is no stale code to replace — dsh loads fresh code
|
|
524
|
+
// itself. Adopt the version.
|
|
525
|
+
// - has a live fiber: the package was already running before we first
|
|
526
|
+
// saw it — it loaded after our boot snapshot, as a bundle entry
|
|
527
|
+
// ordered after this plugin. Its running code may therefore predate
|
|
528
|
+
// this version. Reload it rather than silently adopting a version
|
|
529
|
+
// that never ran (otherwise a late-loaded plugin upgraded before the
|
|
530
|
+
// first cycle keeps its old code forever, with no notice).
|
|
531
|
+
if (!snap[pkg].live.length) {
|
|
532
|
+
versions[pkg] = version;
|
|
533
|
+
continue;
|
|
534
|
+
}
|
|
535
|
+
// fall through: treat as changed and reload
|
|
516
536
|
}
|
|
517
537
|
if (versions[pkg] === version) continue;
|
|
518
538
|
// A version whose reload failed is never re-attempted: each attempt tears
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-hot-reload",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Live-reload upgraded DeepSeek Harness (dsh) plugins without restarting dsh \u2014 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.",
|
|
6
6
|
"keywords": [
|