dsh-crossterm 0.8.5 → 0.8.6
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 +16 -0
- package/README.md +14 -8
- package/client/client.js +6 -4
- package/lib/bus.js +1 -1
- package/lib/cloud/match.js +1 -0
- package/lib/index.js +3 -2
- package/lib/web.js +25 -5
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# dsh-crossterm 变更记录
|
|
2
2
|
|
|
3
|
+
## 0.8.6 — 2026-10-19
|
|
4
|
+
|
|
5
|
+
### 云端设备列表:只列别人,带权限和状态
|
|
6
|
+
|
|
7
|
+
- **不显示本机**:`/crossterm/api/devices` 与卡片「云端设备」行都过滤掉本机 ——
|
|
8
|
+
本机已经在「当前终端」一栏,列在设备里等于把自己当远端。
|
|
9
|
+
- **每台标角色**:`annotateDevices(list, { selfId, ownerDevice })`(`lib/web.js` 导出,纯函数可测);
|
|
10
|
+
角色取云端 `_account.json` 的 `ownerDevice`:是它 → **管理员**,其余 → **成员**。
|
|
11
|
+
- **离线时间口径修正**:以前只读 `updatedAt`,新布局心跳写的是 `at`,离线设备全显示「未知」;
|
|
12
|
+
现在按 `updatedAt → at → lastSeen` 依次取,显示「x 分钟前」。
|
|
13
|
+
- **`term_list` 云端行带角色**:`lib/cloud/match.js` 的 `deviceRow()` 增 `role`;
|
|
14
|
+
`Term.cloudDevices()` 过滤本机,跨设备匹配更干净。
|
|
15
|
+
- 探针 `probe-devices-086.mjs` **11 PASS**(排除本机、剔除无 nodeId、管理员/成员、字段保留、
|
|
16
|
+
at 三种来源、已有 role 不覆盖、空列表)。
|
|
17
|
+
- **要不要跟着动手:不用**(纯展示改动,装上即可)。
|
|
18
|
+
|
|
3
19
|
## 0.8.5 — 2026-10-19
|
|
4
20
|
|
|
5
21
|
### 负责人留痕 + 运行日志可查(日志轮转)
|
package/README.md
CHANGED
|
@@ -28,7 +28,20 @@ A 终端看不到 B 终端里有哪个会话、在干什么,也没法把一条
|
|
|
28
28
|
> `locatePkgJson()` 对子路径行返回 undefined),而插件页顶部标题与这一行共用同一份 `locale/zh.json` 的 meta,
|
|
29
29
|
> 所以它单独做总开关,标题带「(总开关)」;卡片头用 `shortTitle` 显示短名「跨端互通」。
|
|
30
30
|
|
|
31
|
-
**本版更新(0.8.
|
|
31
|
+
**本版更新(0.8.6)**
|
|
32
|
+
|
|
33
|
+
- **云端设备只列「别人」**:卡片里那行不再显示本机(自己已经在「当前终端」一栏),
|
|
34
|
+
只列同一账号下的其他设备,避免把「本机」也当远端看。
|
|
35
|
+
- **每台带权限和状态**:逐台显示 `名称 · 管理员/成员 · 在线/离线(x 分钟前)· v版本号`。
|
|
36
|
+
管理员就是云端 `_account.json` 里 `ownerDevice` 那台;其余都是成员。
|
|
37
|
+
- **离线时间不再显示「未知」**:以前只认 `updatedAt`,新布局心跳写的是 `at`,
|
|
38
|
+
于是离线设备一律「未知」;现在按 `updatedAt → at → lastSeen` 依次取,显示「x 分钟前」。
|
|
39
|
+
- **`term_list` 的云端行也带角色**:agent 侧看到的云端设备行同样标管理员/成员。
|
|
40
|
+
- 纯展示改动,装上即可,无需改动配置。
|
|
41
|
+
|
|
42
|
+
**上一版(0.8.5)**
|
|
43
|
+
|
|
44
|
+
|
|
32
45
|
|
|
33
46
|
- **负责人写清楚、换人及时更正**:新增 `MAINTAINERS.md`(任期表 + 换人步骤 + 机器可读注释)。
|
|
34
47
|
当前负责人 `session-b6aa099b…`(TS-01),助手 `session-ccf34a5a…`(同端多会话2),
|
|
@@ -40,13 +53,6 @@ A 终端看不到 B 终端里有哪个会话、在干什么,也没法把一条
|
|
|
40
53
|
接口是 `GET /crossterm/api/logs?lines=120`(需接口令牌),同时返回归档清单与最近 10 条负责人变更。
|
|
41
54
|
- 卡片新增「维护者」一栏,直接显示当前负责人(含上一任与交卸时间)。
|
|
42
55
|
|
|
43
|
-
**上一版(0.8.4)**
|
|
44
|
-
|
|
45
|
-
- **修统计口径**:0.8.3 卡片一度显示 `已归档 0/24 · 活跃中 38/10`,现在按「状态里有字节」算已备,
|
|
46
|
-
恢复成 `已归档 24/24 · 活跃中 10/10`。
|
|
47
|
-
- 备份行为本身没变:归档会话仍然只传一次,活跃会话仍按水位增量。
|
|
48
|
-
- **活跃会话照旧增量**:从 `_session.json` 的水位往后传,不会重传整份。
|
|
49
|
-
|
|
50
56
|
**上一版(0.8.2)**
|
|
51
57
|
|
|
52
58
|
- 死信按 20s / 1m / 5m / 15m / 1h 退避,8 次后进 `dead/`;收件人写设备名会回退「最近活跃会话」;
|
package/client/client.js
CHANGED
|
@@ -175,13 +175,15 @@ window.__ModuleLoader__.load({
|
|
|
175
175
|
if (!(status && status.cloud && status.cloud.configured)) return "未连接云盘";
|
|
176
176
|
if (!devices || devices.loading) return "读取中…";
|
|
177
177
|
if (!devices.ok) return devices.message || "读取失败";
|
|
178
|
-
const list = devices.devices || [];
|
|
178
|
+
const list = (devices.devices || []).filter((d) => d && (!devices.me || d.nodeId !== devices.me));
|
|
179
179
|
if (!list.length) return "云端还没有其他设备";
|
|
180
180
|
return list
|
|
181
181
|
.map((d) => {
|
|
182
|
-
const label =
|
|
183
|
-
const
|
|
184
|
-
|
|
182
|
+
const label = d.name || d.nodeId || "未知设备";
|
|
183
|
+
const role = d.role || "成员";
|
|
184
|
+
const at = d.updatedAt || d.at || (d.lastSeen ? Date.parse(d.lastSeen) : 0);
|
|
185
|
+
const state = d.online ? "在线" : agoText(at);
|
|
186
|
+
return label + " · " + role + " · " + state + (d.version ? " · v" + d.version : "");
|
|
185
187
|
})
|
|
186
188
|
.join(";");
|
|
187
189
|
}
|
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.8.
|
|
26
|
+
export const VERSION = '0.8.6'
|
|
27
27
|
|
|
28
28
|
/** DSH 的家目录:与宿主其它状态(sessions / profiles)同一个根,多终端天然共享 */
|
|
29
29
|
export function dshHome() {
|
package/lib/cloud/match.js
CHANGED
package/lib/index.js
CHANGED
|
@@ -348,12 +348,13 @@ class CrossTerm {
|
|
|
348
348
|
|
|
349
349
|
// ── 云端设备(跨设备投递,0.7.3 起)─────────────────────────────────
|
|
350
350
|
|
|
351
|
-
/**
|
|
351
|
+
/** 云端设备列表:没连云端、没布局、或还读不到时统一回空数组(0.8.6 起不含本机) */
|
|
352
352
|
async cloudDevices() {
|
|
353
353
|
if (!this.home) return []
|
|
354
354
|
try {
|
|
355
355
|
const r = await this.home.devices()
|
|
356
|
-
|
|
356
|
+
const list = r && r.ok && Array.isArray(r.devices) ? r.devices : []
|
|
357
|
+
return list.filter((d) => d && d.nodeId && d.nodeId !== this.nodeId)
|
|
357
358
|
} catch (e) {
|
|
358
359
|
this.warn(`cloudDevices: ${(e && e.message) || String(e)}`)
|
|
359
360
|
return []
|
package/lib/web.js
CHANGED
|
@@ -8,7 +8,7 @@ import { fileURLToPath } from 'node:url'
|
|
|
8
8
|
import { spawn } from 'node:child_process'
|
|
9
9
|
import { VERSION, readConfig, writeConfig } from './bus.js'
|
|
10
10
|
import { createPan } from './cloud/pan.js'
|
|
11
|
-
import { listCloudDevices
|
|
11
|
+
import { listCloudDevices } from './cloud/devices.js'
|
|
12
12
|
import { listPresences } from './cloud/presence.js'
|
|
13
13
|
import { runSetup } from './cloud/setup.js'
|
|
14
14
|
import { listLogs, tailLogs, readMaintainersDoc, listOwnership } from './logs.js'
|
|
@@ -158,6 +158,22 @@ function cloudProvider(cfg) {
|
|
|
158
158
|
return { id: 'none', name: '未连接', configured: false }
|
|
159
159
|
}
|
|
160
160
|
|
|
161
|
+
/**
|
|
162
|
+
* 云端设备列表的展示口径(0.8.6 起):
|
|
163
|
+
* - 不显示本机(自己已经在「当前终端」那一行);
|
|
164
|
+
* - 每台标上账号里的角色:`_account.json` 的 `ownerDevice` 是管理员,其余是成员;
|
|
165
|
+
* - 保底字段:`role` / `online` / `at`(离线时卡片用它算「x 分钟前」)。
|
|
166
|
+
*/
|
|
167
|
+
export function annotateDevices(list, { selfId = '', ownerDevice = '' } = {}) {
|
|
168
|
+
return (Array.isArray(list) ? list : [])
|
|
169
|
+
.filter((d) => d && d.nodeId && d.nodeId !== selfId)
|
|
170
|
+
.map((d) => ({
|
|
171
|
+
...d,
|
|
172
|
+
role: d.role || (d.nodeId === ownerDevice ? '管理员' : '成员'),
|
|
173
|
+
at: Number(d.at || 0) || (d.lastSeen ? Date.parse(d.lastSeen) || 0 : 0) || (d.updatedAt ? Number(d.updatedAt) || 0 : 0),
|
|
174
|
+
}))
|
|
175
|
+
}
|
|
176
|
+
|
|
161
177
|
/** 语义化版本比较:只比 主.次.补(忽略预发布尾巴),a>b 返回正数 */
|
|
162
178
|
function compareVersion(a, b) {
|
|
163
179
|
const num = (v) => String(v || '').split('-')[0].split('.').map((x) => parseInt(x, 10) || 0)
|
|
@@ -623,12 +639,16 @@ export function registerWeb(ctx, term, log) {
|
|
|
623
639
|
const byId = new Map()
|
|
624
640
|
for (const d of result.devices || []) byId.set(d.nodeId, d)
|
|
625
641
|
for (const d of fresh.devices || []) byId.set(d.nodeId, { ...byId.get(d.nodeId), ...d, source: 'layout' })
|
|
626
|
-
|
|
642
|
+
// 0.8.6:列表里不显示本机,只给「其他设备」;每台标上账号里的角色(管理员 = _account.json 的 ownerDevice)
|
|
643
|
+
const ownerDevice = (layout && layout.accountInfo && layout.accountInfo.ownerDevice) || (layout && layout.deviceId) || ''
|
|
644
|
+
const selfId = info.nodeId || ''
|
|
645
|
+
result.devices = annotateDevices([...byId.values()], { selfId, ownerDevice }).sort(
|
|
646
|
+
(a, b) => Number(b.lastSeen ? Date.parse(b.lastSeen) : b.at || 0) - Number(a.lastSeen ? Date.parse(a.lastSeen) : a.at || 0),
|
|
647
|
+
)
|
|
627
648
|
delete result.tmpFiles
|
|
628
649
|
result.files = (result.files || 0) + (fresh.files || 0)
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
json(res, 200, { ...result, configured: true, me: info.nodeId || '' })
|
|
650
|
+
result.ownerDevice = ownerDevice
|
|
651
|
+
json(res, 200, { ...result, configured: true, me: selfId })
|
|
632
652
|
} catch (error) {
|
|
633
653
|
json(res, 200, {
|
|
634
654
|
ok: false,
|