@hyzyn/dsh-tty 0.20.1 → 0.21.0

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 CHANGED
@@ -97,7 +97,7 @@ Both were reproduced on **Windows 11 ARM (24H2) + Node 22 ARM64**. The fix:
97
97
  on Windows, and its `_deferNoArgs` re-throws that error from a socket callback, where the caller’s
98
98
  try/catch cannot see it.
99
99
 
100
- ## Agent tools (P1)
100
+ ## Agent tools
101
101
 
102
102
  The plugin injects sixteen tools into the agent (with the same power as the bash tool; operations show up live in the user’s terminal):
103
103
 
@@ -248,6 +248,11 @@ references one connection-book entry (host and authentication come with it), in
248
248
  SSH connection), and tunnels keep running with the panel closed; SSH disconnects reconnect automatically
249
249
  with exponential backoff (1s→15s cap), and the remote direction re-runs forwardIn after a reconnect; after
250
250
  the connection-book password changes, a reconnect uses the new credentials automatically;
251
+ - **Profiles running side by side must offset their localPort**: port forwarding is a **machine-level**
252
+ resource, while the configuration is stored per profile (copying a profile copies its tunnels too). Two
253
+ profiles running the same tunnel at the same time leave the later one with `EADDRINUSE`, stuck in
254
+ `error` with `fatal:true` (**no retry**; changing the configuration rebuilds it from the new spec). The
255
+ error message names “possibly the host process of another DSH profile” and offers two ways out;
251
256
  - **Status badges**: while the card is expanded it polls live status every 2s (active green/connecting
252
257
  blue/error red/stopped grey + last error); connection-book entries in the “+” menu show a `⇄N` tunnel
253
258
  badge; the agent can query status with the `tunnel_list` tool;
@@ -597,6 +602,12 @@ ctx.inject(['ttyConnbar'], (c) => {
597
602
  | `requestRender()` | Asks tty to re-render the connection bar (for when a consumer has new data asynchronously and needs the button to appear immediately) |
598
603
 
599
604
  - It only fires on **SSH tabs**; the connection bar of a local tab is hidden anyway.
605
+ - **Command tabs do not fire it** (`spawnSpec.command` non-empty, i.e. a tab running a command through
606
+ `ttyTerminal.open`, such as dsh-docker’s `docker exec -it …`): those connection-bar extensions act on
607
+ **the connection itself**, and hanging them on a command tab would mislead (SFTP would browse the host,
608
+ not the inside of the container the user has in mind). Built-in and third-party actions are hidden
609
+ together; the reopen entry point for an exited tab is not affected — the terminal body already carries a
610
+ “click to reopen” overlay.
600
611
  - A throwing factory is only logged with `console.warn`, without affecting the connection bar or the built-in buttons.
601
612
  - The service name `ttyConnbar` is not declared on tty’s `Context` type surface, so consumers can inject it by
602
613
  string; when tty is not installed or is older than 0.13.0 the injection never fires, so consumers must treat
@@ -730,6 +741,22 @@ ctx.inject(['ttyPanel'], (c) => {
730
741
  - The title bar (title / collapse / ✕) is provided by tty, and consumers only own their own body; a throwing
731
742
  `onClose` is only logged with `console.warn`, without affecting closing the panel.
732
743
 
744
+ **`minimize()` (contract v2)** folds the whole terminal panel away: the modal is hidden, but the DOM /
745
+ WebSocket / xterm buffers are all kept and **the session keeps running**; restoring it goes through the badge
746
+ on the sidebar’s “Terminal” entry. Consumers use it to “give the stage back” — the typical case is dsh-docker
747
+ handing the logs over to the session and folding the terminal away automatically, so the user sees the session
748
+ directly instead of staring at a modal covering it and guessing “did my click do nothing?”. The return value is
749
+ the minimized state after the call, which the caller uses to decide whether its message still needs to say
750
+ “the session is behind the panel”.
751
+
752
+ ```js
753
+ ctx.inject(['ttyPanel'], (c) => {
754
+ if (Number(c.ttyPanel.version ?? 0) < 2 || typeof c.ttyPanel.minimize !== 'function') return false
755
+ if (c.ttyPanel.isOpen() !== true) return false
756
+ return c.ttyPanel.minimize() // fold the terminal away so the session shows through
757
+ })
758
+ ```
759
+
733
760
  > Contract versions: `ttyConnbar.version === 1`, `ttyTerminal.version === 3` (1 = `open` only,
734
761
  > 2 = adds `mount`, 3 = `open` reuses an existing live tab for the same connection + command by default),
735
762
  > `ttyPanel.version === 2` (1 = `mountPane` + `isOpen`, 2 = adds `minimize`). Consumers **decide capabilities
package/README.md CHANGED
@@ -91,7 +91,7 @@ dsh plugin --profile web add link:$(pwd)/packages/tty # 仓库开发调试
91
91
  出现的问题——node-pty 在 Windows 上不接受 signal,而它的 `_deferNoArgs` 会把这个异常推迟到
92
92
  socket 回调里抛出,调用方的 try/catch 拦不住。
93
93
 
94
- ## agent 工具(P1)
94
+ ## agent 工具
95
95
 
96
96
  插件向 agent 注入十六个工具(与 bash 工具同权,操作实时显示在用户终端里):
97
97
 
@@ -112,7 +112,7 @@ dsh plugin --profile web add link:$(pwd)/packages/tty # 仓库开发调试
112
112
  | `sftp_rename` | 重命名/移动远程文件或目录(`to` 与 `from` 不同目录即移动;不覆盖已存在的目标) |
113
113
  | `sftp_remove` | 删除远程文件/目录;目录默认 rmdir(非空明确报错),`recursive:true` 整树删除(不可恢复);会拒绝 `/`、`~`、含 `.`/`..` 段的路径(不可恢复操作的前置护栏,0.19.0) |
114
114
  | `sftp_tree` | 递归列举远程目录结构(深度优先、目录优先;`maxDepth` 1~8 / `maxEntries` 1~2000 限流,超限 `truncated:true`;symlink 不跟随防环) |
115
- | `tunnel_list` | 列出端口转发隧道及其实时状态(活跃/连接中/错误/停止、规则、连接数) |
115
+ | `tunnel_list` | 列出端口转发隧道及其实时状态(活跃/连接中/错误/停止、规则、连接数);`fatal:true` = 人工介入级故障(本地监听失败 / 连接簿缺失),**不会自动重试**,修配置后重建 |
116
116
 
117
117
  典型 agent 流程(推荐):`tty_open` 开一个会话(长驻进程用 `persistName` 要 tmux 持久化)
118
118
  → `tty_send` 启动命令 → `tty_expect` 等就绪标记 → `tty_capture{last:true}` 拿单条命令结果
@@ -220,7 +220,13 @@ SSH 会话同表调度:`tty_list` 里 `kind: 'ssh'` 的条目按 `target`
220
220
  dev server 暴露给远程/内网;
221
221
  - **宿主自持生命周期**:隧道与终端标签互相独立(各有各的 SSH 连接),面板
222
222
  关了隧道照跑;SSH 断线自动指数退避重连(1s→15s 封顶),remote 方向重连
223
- 后自动重新 forwardIn;连接簿改密码后重连自动用新凭证;
223
+ 后自动重新 forwardIn;连接簿改密码后重连自动用新凭证。**例外**:本地监听失败
224
+ (端口被占等)/ 连接簿条目缺失是人工介入级故障——状态停在 `error` 且
225
+ `fatal:true`、**不会自动重试**,改配置(或恢复条目)后按新规格重建(见 DEFECTS D58);
226
+ - **多 profile 同跑要错开 localPort**:端口转发是**机器级**资源,而配置按 profile
227
+ 各存一份(复制 profile 会连隧道一起拷走)。两个 profile 同时跑同一条隧道 → 后起的
228
+ 那个 `EADDRINUSE`,状态停在 `error` 且 `fatal:true`(**不重试**,改配置后按新规格
229
+ 重建);报错文案会直接点明「可能是另一个 DSH profile 的宿主进程」并给出两条出路;
224
230
  - **状态徽标**:卡片展开期间 2s 轮询实时状态(活跃绿/连接中蓝/错误红/停止
225
231
  灰 + 最近错误);「+」菜单的连接簿条目显示 `⇄N` 隧道徽标;agent 可用
226
232
  `tunnel_list` 工具查询状态;
@@ -313,6 +319,10 @@ subsystem,宿主半体 `src/sftp.ts`):
313
319
  tmux server(专用 socket `dsh-tty`,与用户自己的 tmux 完全隔离),断线保活
314
320
  超时、甚至宿主重启后都能接回:
315
321
 
322
+ > ⚠️ **socket 是全 profile 共用的**(`tmux -L dsh-tty`,不随 profile 区分)。多 profile
323
+ > 同跑时:`tty_list` 的持久会话清单会**跨 profile** 出现;而「改 tmux 配置后生效」用的
324
+ > `tmux -L dsh-tty kill-server` 会**一并杀掉另一个 profile 的持久会话**。
325
+
316
326
  - **入口(0.10.1 简化)**:设置卡片「会话持久化」选 `tmux` 即唯一开关——开启后
317
327
  **所有新开的标签默认持久化**:「+」菜单的「本地终端」、连接簿条目点击、
318
328
  SSH 连接对话框(「持久会话」默认勾选,单次连接可取消)。不再有单独的