@hyzyn/dsh-tty 0.19.1 → 0.19.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/README.en.md +21 -9
- package/README.md +16 -7
- package/client.js +40 -33
- package/lib/stats.d.ts +22 -1
- package/lib/stats.js +117 -49
- package/lib/stats.js.map +1 -1
- package/package.json +1 -1
- package/scripts/preview/harness.js +27 -0
- package/scripts/preview/mock-host.js +3 -1
- package/scripts/preview.mjs +1 -0
package/README.en.md
CHANGED
|
@@ -179,12 +179,12 @@ lacks that service the box is switched back off and disabled, with a note that o
|
|
|
179
179
|
empty or 22 (the default)** — matching the connecting side's `spec.port ?? 22` (empty means 22), so
|
|
180
180
|
“empty / `22` / `" 22 "`” all collapse into one key and the same account never ends up with two names or one
|
|
181
181
|
password stored twice; a non-default port does take part (the same host on another port is often a different
|
|
182
|
-
box behind NAT). `field` is `PASSWORD` / `PASSPHRASE`; e.g. `hsadmin@192.
|
|
182
|
+
box behind NAT). `field` is `PASSWORD` / `PASSPHRASE`; e.g. `hsadmin@192.0.2.10:22` →
|
|
183
183
|
`DSH_TTY_HSADMIN_192_168_80_248_PASSWORD`. It is **derived from the resource identity and carries no hash** — the
|
|
184
184
|
same school as git-credential-store's `protocol://username@host` and docker credential helpers'
|
|
185
185
|
`ServerURL` + `Username`: host and username **are ASCII identifiers already**, so nothing needs sanitizing and
|
|
186
186
|
nothing needs a hash to disambiguate. The old hash-based version was patching over "sanitize a human label into a
|
|
187
|
-
key": the reference grammar accepts ASCII only, so `HS 248` / `
|
|
187
|
+
key": the reference grammar accepts ASCII only, so `HS 248` / `lab-a` / `HS_248` collapse to exactly the same
|
|
188
188
|
string and only a hash could stop them silently overwriting each other. A resource identity has no such trap — a
|
|
189
189
|
collision can only happen for **the same host, the same user, the same port**, which is the same password by
|
|
190
190
|
definition (sharing it is correct behaviour). **The connection name never takes part in the key**, so renaming a
|
|
@@ -491,12 +491,24 @@ session belongs to (visually aligned with FinalShell’s session monitor bar):
|
|
|
491
491
|
session exit, orphan reaping, plugin disable and configuration off all stop the meter and close the remote
|
|
492
492
|
channel, leaving no timers or remote loops.
|
|
493
493
|
- **Best-effort**: a field that cannot be obtained is omitted (the frontend shows “n/a”); a collection
|
|
494
|
-
failure silently stops the meter and hides the whole status bar (it collapses after
|
|
495
|
-
frame
|
|
496
|
-
|
|
494
|
+
failure silently stops the meter and hides the whole status bar (it collapses after **8s** without a new
|
|
495
|
+
frame — not 3s: when a sampling subprocess on the host occasionally slows down, frames get further apart,
|
|
496
|
+
and too tight a window makes the whole bar blink) — it never writes to the PTY and never raises an error.
|
|
497
|
+
Progress-bar thresholds: <70 normal / 70~90 yellow / >90 red.
|
|
498
|
+
- **A slow command cannot stall the cadence**: subprocess-backed fields (df / netstat / vm_stat) are awaited
|
|
499
|
+
only on the very first sample; afterwards the sampler uses the last known value and refreshes in the
|
|
500
|
+
background, so a command that hangs on some machine only leaves that one field briefly stale instead of
|
|
501
|
+
stretching the one-frame-per-second timeline (measured: 3000ms → 3~12ms per frame).
|
|
497
502
|
- **Hot effect**: turning `statsEnabled` off stops collection at once (the status bar disappears and no more
|
|
498
503
|
stats frames go over the WS), and turning it back on restores automatically from the subscriptions still in
|
|
499
504
|
place — no restart and no need to reopen tabs.
|
|
505
|
+
- **Fixed slots + incremental repaint**: every value owns a fixed-width character slot (right
|
|
506
|
+
aligned, so even the widest form only takes that one slot), and the items are built once — afterwards only
|
|
507
|
+
text that actually changed is written. Hence `CPU 5% → 12%`, `TCP 36 → 1024` and
|
|
508
|
+
`memory 9.2 GB → 17.8 GB` no longer push every following item sideways (which showed up as the whole bar
|
|
509
|
+
jumping once a second), the progress-bar width can finally animate through its CSS transition, and
|
|
510
|
+
horizontally scrolling to `Network` in a narrow window is no longer snapped back to the start by the next
|
|
511
|
+
refresh.
|
|
500
512
|
|
|
501
513
|
## Configuration (Settings → Plugins → “Terminal Panel”, saving takes effect immediately)
|
|
502
514
|
|
|
@@ -559,7 +571,7 @@ single command** (the typical use is dsh-docker’s card “Terminal” button
|
|
|
559
571
|
ctx.inject(['ttyTerminal'], (c) => {
|
|
560
572
|
c.ttyTerminal.open({
|
|
561
573
|
command: "docker exec -it 'ems-consumer-test' sh", // required, single line, ≤2000 characters
|
|
562
|
-
book: '
|
|
574
|
+
book: 'lab-a', // one of the two: connection-book entry name → SSH tab
|
|
563
575
|
// spec: { host, port, username, auth, agentForward }, // inline SSH fields
|
|
564
576
|
// (neither = local tab, with cwd giving the working directory)
|
|
565
577
|
label: 'ems-consumer-test · exec',
|
|
@@ -592,7 +604,7 @@ ctx.inject(['ttyTerminal'], (c) => {
|
|
|
592
604
|
if (Number(c.ttyTerminal.version ?? 0) < 2) { /* older version: fall back to open */ }
|
|
593
605
|
const dispose = c.ttyTerminal.mount(hostEl, {
|
|
594
606
|
command: "docker exec -it 'ems-consumer-test' sh", // the same set of options as open
|
|
595
|
-
book: '
|
|
607
|
+
book: 'lab-a', // book > spec > local
|
|
596
608
|
label: 'ems-consumer-test · exec',
|
|
597
609
|
})
|
|
598
610
|
// When collapsing your own drawer:
|
|
@@ -628,8 +640,8 @@ A mount slot is **connection-scoped**: its credentials / target come from the te
|
|
|
628
640
|
So since 0.19.0 every pane records its **owner tab** (`options.ownerSid`, defaulting to the active tab at
|
|
629
641
|
mount time): switching to another tab **hides** the pane (`data-dock-hidden`; its DOM and your rendered tree
|
|
630
642
|
survive, in-flight transfers keep running) and switching back restores the scene; closing the owner tab tears
|
|
631
|
-
the pane down. Without this, the pane stayed put across a tab switch — its title read `SFTP ·
|
|
632
|
-
while the active tab was `192.
|
|
643
|
+
the pane down. Without this, the pane stayed put across a tab switch — its title read `SFTP · lab-b`
|
|
644
|
+
while the active tab was `192.0.2.10`, leaving **another host**’s file listing on screen (worst case:
|
|
633
645
|
uploading to the wrong host). Passing `ownerSid: null` means “owned by no tab” (always visible); that is what
|
|
634
646
|
happens automatically when the panel is open with no tabs at all, and a consumer can use it to declare “this
|
|
635
647
|
pane has nothing to do with tabs, do not hide it on a switch”.
|
package/README.md
CHANGED
|
@@ -166,12 +166,12 @@ SSH 会话同表调度:`tty_list` 里 `kind: 'ssh'` 的条目按 `target`
|
|
|
166
166
|
- **名字**(规则恒定):`DSH_TTY_<用户名>_<主机>[_<端口>]_<字段>`,**端口留空或 22(默认)时省略**
|
|
167
167
|
—— 与连接侧的 `spec.port ?? 22` 一致(留空即 22),所以"留空 / `22` / `" 22 "`"三种写法归成同一个键,
|
|
168
168
|
同一个账号不会有两个名字、同一个密码不会存两份;非默认端口进键(同一主机不同端口常是 NAT 后面的
|
|
169
|
-
不同盒子)。字段 = `PASSWORD` / `PASSPHRASE`;例 `hsadmin@192.
|
|
169
|
+
不同盒子)。字段 = `PASSWORD` / `PASSPHRASE`;例 `hsadmin@192.0.2.10:22` →
|
|
170
170
|
`DSH_TTY_HSADMIN_192_168_80_248_PASSWORD`。**按资源身份派生、不带哈希**——与
|
|
171
171
|
git-credential-store 的 `protocol://username@host`、docker credential helpers 的
|
|
172
172
|
`ServerURL` + `Username` 同一派:host 与 username **本来就是 ASCII 标识符**,不需要清洗、
|
|
173
173
|
也就不需要哈希兜底。曾经的哈希版是在补救"把人类标签清洗成键":引用文法只认 ASCII,
|
|
174
|
-
`HS 248` / `
|
|
174
|
+
`HS 248` / `lab-a` / `HS_248` 折出来完全一样,只能靠哈希避免静默覆盖 ✗。资源身份没有这个
|
|
175
175
|
死结——撞名只可能发生在**同一主机、同一用户、同一端口**,而那本来就该是同一个密码(共享是
|
|
176
176
|
正确行为)。**连接名完全不参与键**,所以改连接名/改备注都不会换键。空主机或空用户名则拒绝
|
|
177
177
|
存入(键的全部来源,缺一就退化成常量)。代价是可读性弱于人类标签:本对话框的「存入」**只按
|
|
@@ -436,10 +436,19 @@ tmux server(专用 socket `dsh-tty`,与用户自己的 tmux 完全隔离)
|
|
|
436
436
|
宿主首个订阅才起采集;退订清零、会话退出、孤儿回收、插件禁用、配置关闭
|
|
437
437
|
都会停表并关掉远端 channel,不留定时器/远端循环。
|
|
438
438
|
- **best-effort**:某项拿不到就省略该字段(前端显示「无」),采集失败静默停表、
|
|
439
|
-
状态条整条隐藏(
|
|
439
|
+
状态条整条隐藏(8s 收不到新帧即收起——**不是 3s**:宿主某个采集子进程偶发变慢时帧间隔
|
|
440
|
+
会被拉长,窗口太紧就会整条一闪一闪)——绝不写 PTY、绝不弹错误。进度条阈值
|
|
440
441
|
配色:<70 正常 / 70~90 黄 / >90 红。
|
|
442
|
+
- **慢命令不拖垮节奏**:走子进程的字段(df / netstat / vm_stat)只在首次采样时等一次,
|
|
443
|
+
之后一律「用上一次的值 + 到点后台刷新」,某台机器某个命令卡住只会让那一格短暂显示旧值,
|
|
444
|
+
不会把「每秒一帧」的时间轴拖散(实测 3000ms/帧 → 3~12ms/帧)。
|
|
441
445
|
- **热生效**:关掉 `statsEnabled` 立刻停采集(状态条消失、WS 不再发 stats 帧),
|
|
442
446
|
重新打开后按仍存留的订阅自动恢复,无需重启或用例重开标签。
|
|
447
|
+
- **固定槽位 + 增量刷新**:每个值的字符槽位固定(右对齐,最宽的一档照样只占
|
|
448
|
+
自己那一格),条目只建一次、之后只写真的变了的文本。所以 `CPU 5% → 12%`、
|
|
449
|
+
`TCP 36 → 1024`、`内存 9.2 GB → 17.8 GB` 都不会把后面的条目推着横移(曾表现为整条
|
|
450
|
+
每秒跳一次),进度条宽度也能真正走 CSS 过渡;窄窗口下横向滚到右侧看 `网络` 时,
|
|
451
|
+
滚动位置不会被下一秒的刷新弹回开头。
|
|
443
452
|
|
|
444
453
|
## 配置(设置 → 插件 → 终端面板,保存即热生效)
|
|
445
454
|
|
|
@@ -516,7 +525,7 @@ ctx.inject(['ttyConnbar'], (c) => {
|
|
|
516
525
|
ctx.inject(['ttyTerminal'], (c) => {
|
|
517
526
|
c.ttyTerminal.open({
|
|
518
527
|
command: "docker exec -it 'ems-consumer-test' sh", // 必填,单行,≤2000 字符
|
|
519
|
-
book: '
|
|
528
|
+
book: 'lab-a', // 二选一:连接簿条目名 → SSH 标签
|
|
520
529
|
// spec: { host, port, username, auth, agentForward }, // 内联 SSH 字段
|
|
521
530
|
// (都不传 = 本地标签,用 cwd 指定工作目录)
|
|
522
531
|
label: 'ems-consumer-test · exec',
|
|
@@ -546,7 +555,7 @@ ctx.inject(['ttyTerminal'], (c) => {
|
|
|
546
555
|
if (Number(c.ttyTerminal.version ?? 0) < 2) { /* 老版本:退回 open */ }
|
|
547
556
|
const dispose = c.ttyTerminal.mount(hostEl, {
|
|
548
557
|
command: "docker exec -it 'ems-consumer-test' sh", // 与 open 同一套 options
|
|
549
|
-
book: '
|
|
558
|
+
book: 'lab-a', // book > spec > 本地
|
|
550
559
|
label: 'ems-consumer-test · exec',
|
|
551
560
|
})
|
|
552
561
|
// 收起自己的抽屉时:
|
|
@@ -578,7 +587,7 @@ ctx.inject(['ttyTerminal'], (c) => {
|
|
|
578
587
|
pane 记一个「归属标签」(`options.ownerSid`,默认 = 挂载那一刻的活动标签):切到别的
|
|
579
588
|
标签时整块**收起**(`data-dock-hidden`,DOM 与你 render 的树都保活,在途传输继续跑),
|
|
580
589
|
切回来恢复现场;归属标签被关掉时 pane 一并收掉。不这么做的话,切完标签面板还停在原处
|
|
581
|
-
——标题写着 `SFTP ·
|
|
590
|
+
——标题写着 `SFTP · lab-b`、底下活动标签却是 `192.0.2.10`,面板里躺着**另一台
|
|
582
591
|
主机**的文件列表(最坏的情况是往错主机上传)。显式传 `ownerSid: null` 表示「不隶属任何
|
|
583
592
|
标签」(一直可见)——面板开着但一个标签都没有时自动落进这一档;消费方也可以用它声明
|
|
584
593
|
「这块与标签无关,别跟着切」。
|
|
@@ -781,7 +790,7 @@ node scripts/preview.mjs --theme=light # 浅色主题
|
|
|
781
790
|
- **SSH 密码 / 口令建议 `env:VAR` 引用**:连接簿随 settings 文件落盘,
|
|
782
791
|
`password` / `passphrase` 明文入库有泄露面;建议 `env:VAR` +
|
|
783
792
|
dsh-env-manager 托管,或直接用 `agent` 认证(凭证不落盘)。
|
|
784
|
-
- **服务器状态条(0.17.0)边界**:远端靠两跳兜底:先 POSIX(要 `/proc` + `awk`),一帧未出则回退 PowerShell——**Windows 远端**由此覆盖(温度多数组件没有、显示「无」,磁盘取系统盘 `%SystemDrive%`,TCP 走 `netstat -an`,网速走 `Get-NetAdapterStatistics` 差值;只输出整数,从根上避开区域小数点与科学计数法),**macOS/BSD 远端**两跳都不成立、一个字段都拿不到、状态条整条隐藏;非 Linux 远端的每次(重新)订阅会多一跳注定失败的 exec(约百毫秒,不影响出帧延迟);Linux 上 CPU 温度只在暴露 `/sys/class/thermal` 的机器上有(多数云主机/虚拟机没有,显示「无」);磁盘固定取 `/`(Windows 取系统盘)所在文件系统(不做多挂载点);远端脚本经 `sh -c` 单引号包裹(登录 shell 是 fish/csh 也能跑);本地会话的指标属于**宿主机器**(多个本地标签共享同一份采样,CPU/网速差值窗口连续),macOS 没有 /proc、`ss`、sysfs,改用 os/netstat/vm_stat
|
|
793
|
+
- **服务器状态条(0.17.0)边界**:远端靠两跳兜底:先 POSIX(要 `/proc` + `awk`),一帧未出则回退 PowerShell——**Windows 远端**由此覆盖(温度多数组件没有、显示「无」,磁盘取系统盘 `%SystemDrive%`,TCP 走 `netstat -an`,网速走 `Get-NetAdapterStatistics` 差值;只输出整数,从根上避开区域小数点与科学计数法),**macOS/BSD 远端**两跳都不成立、一个字段都拿不到、状态条整条隐藏;非 Linux 远端的每次(重新)订阅会多一跳注定失败的 exec(约百毫秒,不影响出帧延迟);Linux 上 CPU 温度只在暴露 `/sys/class/thermal` 的机器上有(多数云主机/虚拟机没有,显示「无」);磁盘固定取 `/`(Windows 取系统盘)所在文件系统(不做多挂载点);远端脚本经 `sh -c` 单引号包裹(登录 shell 是 fish/csh 也能跑);本地会话的指标属于**宿主机器**(多个本地标签共享同一份采样,CPU/网速差值窗口连续),macOS 没有 /proc、`ss`、sysfs,改用 os/netstat/vm_stat(网速那条是 `netstat -ibn`——**必须带 `-n`**:不带时 netstat 会对接口地址做反查,DNS 不响应就挂几十秒,D50 的根因就是它),故温度恒为「无」,内存按 vm_stat 的 active+wired+compressed 计(os.freemem 会把文件缓存算成已用、长期 99%);指标是**瞬时值**,没有历史曲线,也不提供 agent 工具(agent 侧仍用 tty_* 命令粒度能力)。
|
|
785
794
|
- **SSH 会话没有本地 pid**:ssh2 shell channel 不是本机进程,`ready.pid`
|
|
786
795
|
为 `null`、`tty_list` 显示 `target` 而非 pid,本机 `ps` / `kill` 对远程
|
|
787
796
|
进程无效——关闭请用标签 ✕ 或 `kill` 帧(关闭的是 ssh2 channel)。
|