dsh-crossterm 0.9.9 → 0.9.10
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 +9 -0
- package/README.md +11 -9
- package/components/session/manifest.json +1 -1
- package/lib/bus.js +20 -1
- package/lib/index.js +6 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
## 0.9.10 — 2026-10-20
|
|
2
|
+
|
|
3
|
+
### 修复:无主链台账收口(清除所有特征码的最后一步)
|
|
4
|
+
|
|
5
|
+
- 现象:本机 `links` 里没有某串码的记录、`chains/<code>.json` 里只剩别的机器早已下线的成员,`term_unlink all=true` 只能回「本终端没有接在特征码上」,台账留在磁盘上没人清。
|
|
6
|
+
- 修法:`lib/bus.js` 新增 `dropChainIfOrphan(code, nodeId)` —— 本节点不在链上、且链上所有成员节点都离线(超过 `offlineAfterMs * 3`)时删掉该链文件;`unlinkChain()` 的 ghost 分支在上一步没摘到成员时调用它,成功返回 `{ ok:true, droppedChain:true }`。
|
|
7
|
+
- 安全性:本节点是成员、或有任一成员在线时一律不删;探针 `probe-0910.mjs` 10 项覆盖四种分支。
|
|
8
|
+
- 组件版本:跨会话 `0.5.1` → `0.5.2`。
|
|
9
|
+
|
|
1
10
|
## 0.9.9 — 2026-10-20
|
|
2
11
|
|
|
3
12
|
### 修复:幽灵链成员退不掉(YOCE_C 报告)
|
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ A 终端看不到 B 终端里有哪个会话、在干什么,也没法把一条
|
|
|
19
19
|
| 顺序 | 组件名称 | 版本 | 作用 | 工具 |
|
|
20
20
|
|---|---|---|---|---|
|
|
21
21
|
| ① | 跨端互通(入口/自更新) | v0.9.3 | 自更新开关:打开后定期检查 npm 新版本并自动安装(默认关;装完要重启 DSH 生效)。关掉它只失去卡片与自动更新,下面四个组件照常工作。裸包名行,承载插件标题/简介与配置卡片,不挂工具 | — |
|
|
22
|
-
| ② | 跨会话 | v0.5.
|
|
22
|
+
| ② | 跨会话 | v0.5.2 | 同一终端里的多个会话之间互通:特征码链、内联邮件、收件箱 | `term_link` `term_unlink` `term_broadcast` `term_inbox` `term_config` |
|
|
23
23
|
| ③ | 跨工作区 | v0.1.0 | 在本机不同工作区、不同会话之间互发邮件与文件(跨终端本轮不做,暂无条件) | `term_whoami` `term_list` `term_send` `term_send_files` |
|
|
24
24
|
| ④ | 跨设备 | v0.4.0 | 经云端中转站,在多台机器的 DSH 之间互发邮件与文件 | `term_cloud` |
|
|
25
25
|
| ⑤ | 自动重启 | v0.3.29 | 改完插件/配置后让 DSH 自己重启一次,并自动拉起离线会话(原 `dsh-restart` 插件,0.9.0 起并入) | `dsh_restart` |
|
|
@@ -30,7 +30,14 @@ A 终端看不到 B 终端里有哪个会话、在干什么,也没法把一条
|
|
|
30
30
|
>
|
|
31
31
|
> 组件版本号怎么升:**只在该组件自己的文件改动时升它**,跟着插件一起发版(例:只改自动重启 → `components/restart` 的 `0.3.28` → `0.3.29`,其余四个不动)。插件总版本仍按发版技能的三分位规则。
|
|
32
32
|
|
|
33
|
-
**本版更新(0.9.
|
|
33
|
+
**本版更新(0.9.10)**
|
|
34
|
+
|
|
35
|
+
- **「清除所有特征码」最后一步收口**:本终端已经不在某串码上、links 里也没有记录、而这串码上的成员全部离线时,`term_unlink ... all=true` 现在会把这份无主台账一并删掉(返回 `droppedChain:true`),不用再人工去删 `chains/<code>.json`。
|
|
36
|
+
- 判定很保守:本节点还在链上、或有任何一个成员节点在线(含刚心跳过),都**不会**删;只清「谁都不在线」的残档。
|
|
37
|
+
- 起因:0.9.9 修好了「台账有本机成员却退不掉」,但还有一种「本机根本没有成员、别的机器早解散了」的残档,之前只能人工删文件(C 盘写入要审批)。
|
|
38
|
+
- 组件版本:跨会话 0.5.1 → **0.5.2**,其余组件不动。
|
|
39
|
+
|
|
40
|
+
**上一版(0.9.9)**
|
|
34
41
|
|
|
35
42
|
- **修「幽灵链成员」退不掉**(YOCE_C 2026-10-20 报的坑):`term_unlink ... all=true` 以前只遍历内存里的 links,遇到「链台账里还留着本终端成员、但 links 已没有这条记录」就永远退不掉(一直回「本终端没有接在特征码上」)。
|
|
36
43
|
- 现在 `all=true` 在 links 为空时也会按 **nodeId** 把本终端在这串码上的成员从台账里摘掉,返回值带 `ghosts`;成员清空时链文件自动删除。
|
|
@@ -38,14 +45,9 @@ A 终端看不到 B 终端里有哪个会话、在干什么,也没法把一条
|
|
|
38
45
|
- 显式传 `sessionId` 的行为不变——只退那一个,不动其它会话(笔误不会误删)。
|
|
39
46
|
- 组件版本:跨会话 0.5.0 → **0.5.1**,其余组件不动。
|
|
40
47
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
- **自动重启组件交回维护权**:原负责人会话「自动重启」按机主指示即日起停止改动,`components/restart/**` 暂由插件负责人 `b6aa099b` 直管;新负责人等后续交接时再任命(`MAINTAINERS.md` 的 `modules.restart` 已改,旧负责人记入任期)。
|
|
44
|
-
- 它交回时留了两条观察,已记进 `MAINTAINERS.md` 的「待定事项」,下次动这个组件前先定口径。
|
|
45
|
-
- 只改 `MAINTAINERS.md` / `CHANGELOG.md` / README,代码与组件版本都不动。
|
|
46
|
-
|
|
47
|
-
**更早(0.9.7 / 0.9.6 / 0.9.5 / 0.9.4 / 0.9.3 / 0.9.2 / 0.9.0 / 0.8.14 / 0.8.13 / 0.8.12 / 0.8.11 / 0.8.10 / 0.8.9 / 0.8.8 / 0.8.7 / 0.8.6 / 0.8.5 / 0.8.0)**
|
|
48
|
+
**更早(0.9.8 / 0.9.7 / 0.9.6 / 0.9.5 / 0.9.4 / 0.9.3 / 0.9.2 / 0.9.0 / 0.8.14 / 0.8.13 / 0.8.12 / 0.8.11 / 0.8.10 / 0.8.9 / 0.8.8 / 0.8.7 / 0.8.6 / 0.8.5 / 0.8.0)**
|
|
48
49
|
|
|
50
|
+
- 0.9.8:自动重启组件维护权交回、暂由插件负责人直管;只改文档。
|
|
49
51
|
- 0.9.7:组件版本按机主要求重新定起点(跨会话 v0.5.0 / 跨设备 v0.4.0 / 跨工作区 v0.1.0)。
|
|
50
52
|
- 0.9.6:去掉「跨账号」组件,插件页变成 5 个组件。
|
|
51
53
|
- 0.9.5:组件「跨终端」改名「跨工作区」(跨终端本轮不做)。
|
package/lib/bus.js
CHANGED
|
@@ -23,7 +23,7 @@ import path from 'node:path'
|
|
|
23
23
|
import crypto from 'node:crypto'
|
|
24
24
|
import { rotateIfNeeded } from './logs.js'
|
|
25
25
|
|
|
26
|
-
export const VERSION = '0.9.
|
|
26
|
+
export const VERSION = '0.9.10'
|
|
27
27
|
|
|
28
28
|
/** DSH 的家目录:与宿主其它状态(sessions / profiles)同一个根,多终端天然共享 */
|
|
29
29
|
export function dshHome() {
|
|
@@ -544,6 +544,25 @@ export class Bus {
|
|
|
544
544
|
return { code, removed, found: true }
|
|
545
545
|
}
|
|
546
546
|
|
|
547
|
+
/**
|
|
548
|
+
* 无主台账清理:本节点不在链上、且链上所有成员所属节点都离线 / 过期时,把这串码的本地台账删掉。
|
|
549
|
+
* 场景:别的机器早就解散了链,本机 links 里也没有它,但 chains/<code>.json 还留着离线成员记录 ——
|
|
550
|
+
* 以前只能人工删文件(C 盘写入要审批),0.9.10 让 term_unlink all=true 顺手收口。
|
|
551
|
+
*/
|
|
552
|
+
async dropChainIfOrphan(code, nodeId) {
|
|
553
|
+
const file = this.chainFile(code)
|
|
554
|
+
const chain = await readJson(file)
|
|
555
|
+
if (!chain || !Array.isArray(chain.members)) return { code, dropped: false, reason: 'no-chain' }
|
|
556
|
+
if (chain.members.some((m) => m.nodeId === nodeId)) return { code, dropped: false, reason: 'self-member' }
|
|
557
|
+
const nodes = await this.listNodes().catch(() => [])
|
|
558
|
+
const alive = new Map(nodes.map((n) => [n.nodeId, Number(n.updatedAt) || 0]))
|
|
559
|
+
const limit = Date.now() - this.cfg.offlineAfterMs * 3
|
|
560
|
+
const anyAlive = chain.members.some((m) => (alive.get(m.nodeId) || 0) >= limit)
|
|
561
|
+
if (anyAlive) return { code, dropped: false, reason: 'member-online', members: chain.members.length }
|
|
562
|
+
await fsp.unlink(file).catch(() => {})
|
|
563
|
+
return { code, dropped: true, members: chain.members.length }
|
|
564
|
+
}
|
|
565
|
+
|
|
547
566
|
/** 剔掉已经不存在的成员(进程退出 / 长时间没心跳) */
|
|
548
567
|
async pruneChain(code, nodes) {
|
|
549
568
|
const chain = await readJson(this.chainFile(code))
|
package/lib/index.js
CHANGED
|
@@ -1191,6 +1191,12 @@ class CrossTerm {
|
|
|
1191
1191
|
await this.note(`unlinked ${norm} [ghost ${ghost.removed}]`)
|
|
1192
1192
|
return { ok: true, code: norm, removed: ghost.removed, ghosts: ghost.removed, empty: !!ghost.empty, sessions: [] }
|
|
1193
1193
|
}
|
|
1194
|
+
// 本终端在台账里也没有成员:如果这串码上的成员全部离线,就当无主台账清掉(0.9.10)
|
|
1195
|
+
const orphan = await this.bus.dropChainIfOrphan(norm, this.nodeId).catch(() => undefined)
|
|
1196
|
+
if (orphan && orphan.dropped) {
|
|
1197
|
+
await this.note(`unlinked ${norm} [orphan chain, ${orphan.members} 个离线成员]`)
|
|
1198
|
+
return { ok: true, code: norm, removed: 0, droppedChain: true, empty: true, sessions: [] }
|
|
1199
|
+
}
|
|
1194
1200
|
}
|
|
1195
1201
|
return { ok: false, detail: `本终端${scope.length ? `的会话 ${this.labelOf(scope[0])}` : ''}没有接在特征码「${norm}」上` }
|
|
1196
1202
|
}
|