@hyzyn/dsh-tty 0.30.0 → 0.32.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 +43 -14
- package/README.md +37 -10
- package/client.js +145 -45
- package/lib/index.d.ts +61 -7
- package/lib/index.js +109 -13
- package/lib/index.js.map +1 -1
- package/lib/shell-integration.d.ts +10 -0
- package/lib/shell-integration.js +148 -7
- package/lib/shell-integration.js.map +1 -1
- package/package.json +1 -1
- package/scripts/preview/harness.js +140 -7
- package/scripts/preview/mock-host.js +19 -0
- package/scripts/preview.mjs +11 -1
- package/scripts/pty-kill-probe.cjs +123 -0
- package/scripts/pty-kill-repro-plugin.mjs +72 -0
- package/scripts/pty-kill-repro.mjs +101 -0
- package/scripts/windows-smoke.mjs +97 -2
package/README.en.md
CHANGED
|
@@ -136,11 +136,22 @@ Both were reproduced on **Windows 11 ARM (24H2) + Node 22 ARM64**. The fix:
|
|
|
136
136
|
no new prompt, looking like “it was sent but never ran”). For **local sessions on win32** the plugin now
|
|
137
137
|
turns a bare LF into CRLF (an existing CRLF is not doubled; non-Windows and SSH sessions pass through
|
|
138
138
|
untouched), so the documented `\n` path just works;
|
|
139
|
-
- **
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
139
|
+
- **Shell integration (OSC 133/7) depends on the shell family**: the **PowerShell family is supported**
|
|
140
|
+
(`powershell.exe` / `pwsh.exe`) through a stable `-File` stub that hooks `prompt` and
|
|
141
|
+
`PSConsoleHostReadLine` — this yields cwd tracking (`tty_list.cwd` following `cd`), exit codes, the
|
|
142
|
+
`running` state and command-granular `tty_expect`. **cmd is not** (it has no command-boundary hooks), so
|
|
143
|
+
the settings card greys the switch out and points at “switch the shell path to PowerShell”. **Known
|
|
144
|
+
limit**: on PowerShell 7 the command output reaches ConPTY *after* the D marker (pane redraws are
|
|
145
|
+
asynchronous and batched — the same root cause as in the tmux case), so `tty_capture{last}` may come back
|
|
146
|
+
empty; use `tty_capture` to read the tail there. Windows PowerShell 5.1 is unaffected (both were measured
|
|
147
|
+
on a real machine). The stub only loads through `-ExecutionPolicy Bypass` (process-scoped); two boundaries
|
|
148
|
+
are recorded as they are: when **Group Policy** locks the execution policy to Restricted / AllSigned that
|
|
149
|
+
parameter does **not** override GPO, so the stub fails to load and the tab opens with integration silently
|
|
150
|
+
absent (the same degradation as “the user turned PSReadLine off”); the parameter also writes the value into
|
|
151
|
+
`$Env:PSExecutionPolicyPreference`, which PowerShell processes started from that session inherit. One more
|
|
152
|
+
known side effect: wrapping `prompt` makes **the user’s original prompt see its own `$?`** as the result of
|
|
153
|
+
our writes (always true), so failure indicators that rely on `$?` stop working;
|
|
154
|
+
- **Two things are not supported** (the host turns them off and the settings card explains why):
|
|
144
155
|
- **tmux persistence**: there is no tmux on Windows, so local tabs open normally but are not managed
|
|
145
156
|
(SSH into a Linux host still works);
|
|
146
157
|
- **Server status bar**: locally only CPU / memory / uptime are available (`node:os`); disk / TCP / network
|
|
@@ -154,7 +165,13 @@ Both were reproduced on **Windows 11 ARM (24H2) + Node 22 ARM64**. The fix:
|
|
|
154
165
|
- **End-to-end coverage (0.19.0)**: `scripts/windows-smoke.mjs` drives a real `cmd.exe` through
|
|
155
166
|
spawn → input echo → kill → respawn on the CI windows-latest runner, plus two links that only hold on
|
|
156
167
|
a real machine (W6: after normalisation a bare LF really does submit in conhost, D74; W7: a `command`
|
|
157
|
-
session that exits turns into read-only retention and `tty_capture` still reads its pre-exit output, D77).
|
|
168
|
+
session that exits turns into read-only retention and `tty_capture` still reads its pre-exit output, D77).
|
|
169
|
+
**W8 (the PowerShell OSC 133/7 stage) runs on CI** (since 2026-10-13): it used to be guarded by the
|
|
170
|
+
**real-machine lane** only, because killing a ConPTY session there tripped `0xC0000374` — the root cause
|
|
171
|
+
(the same PTY being natively `kill()`ed twice) is now located and fixed, see **D100** in
|
|
172
|
+
[DEFECTS.md](./DEFECTS.md) and the 2026-10-13 section of [ROADMAP.md](./ROADMAP.md). Where no PowerShell
|
|
173
|
+
exists the stage honestly reports its own `SKIP` row (excluded from the denominator, never dressed up as
|
|
174
|
+
`12/12`). It caught and now pins a
|
|
158
175
|
Windows-only failure class: force-killing a local PTY crashed the host — node-pty rejects signals
|
|
159
176
|
on Windows, and its `_deferNoArgs` re-throws that error from a socket callback, where the caller’s
|
|
160
177
|
try/catch cannot see it.
|
|
@@ -165,7 +182,7 @@ The plugin injects nineteen tools into the agent (operations show up live in the
|
|
|
165
182
|
|
|
166
183
|
| Tool | Purpose |
|
|
167
184
|
| --- | --- |
|
|
168
|
-
| `tty_list` | List terminal sessions (sid / kind (`local\|ssh`) / target / pid / **cwd tracked live as you `cd`** / activity time; tmux persistent sessions carry a `persist` marker; sessions the agent opened carry `owner: 'agent'`). **Includes sessions whose process has exited but which are still inside their read-only retention window** (`exited:true` + exit code/signal, see below). **`running` says whether a command is currently executing** (true = it is: do not send into it now; false = the command has finished; **omitted = cannot tell** — non-persistent SSH / fish·csh / Windows
|
|
185
|
+
| `tty_list` | List terminal sessions (sid / kind (`local\|ssh`) / target / pid / **cwd tracked live as you `cd`** / activity time; tmux persistent sessions carry a `persist` marker; sessions the agent opened carry `owner: 'agent'`). **Includes sessions whose process has exited but which are still inside their read-only retention window** (`exited:true` + exit code/signal, see below). **`running` says whether a command is currently executing** (true = it is: do not send into it now; false = the command has finished; **omitted = cannot tell** — non-persistent SSH / fish·csh / Windows cmd sessions carry no shell-integration markers, which is *not* the same as “idle”), and the same-source `lastExitCode` / `lastExitAt` are the exit code and end time of “the previous completed command” (0.23.0). The rendered text spells the three states `[空闲]` / `[运行中——现在别往里发命令]` / `[命令状态未知——…]`; **“unknown” also covers one more case** — the host has seen **no marker for that session since this boot** (typically a tmux persistent session already sitting at its prompt before the host restarted): send it a bare Enter or run a command and the marker arrives, turning it into `[空闲]`; non-persistent SSH / fish·csh / Windows cmd sessions never emit markers, so `[命令状态未知]` is their normal state |
|
|
169
186
|
| `tty_open` | **Open a terminal session yourself** (0.20.0): a local shell, or a command via `command` (dev server / watch; it runs as **a whole piece of code in the host shell’s syntax** — on a POSIX shell `cd x && cmd`, `a; b` and multi-line scripts work, while **Windows cmd / PowerShell use their own syntax**; the current shell and syntax are restated every turn in the systemPrompt terminal line; it is *not* subject to the “single line ≤2000” client rule below — D78), with optional tmux persistence via `persistName`. The session **shows up in the user’s terminal panel** as an ordinary tab the user can see and take over — never a hidden session |
|
|
170
187
|
| `tty_close` | Close a session opened by `tty_open` (0.20.0). **Only the agent’s own sessions may be closed**: a tab the user opened is refused, so the agent never ends a terminal the user is working in. It also works on an **exited session that is still in read-only retention** — that is its release entry point (by default it is retained **until explicitly closed**, never on a timer) |
|
|
171
188
|
| `tty_run` | **One-shot command** (0.23.0): open a session, run `command`, wait for it to finish and return the tail output + exit code directly — collapsing “`tty_open` → wait → `tty_capture{last}` → `tty_close`” into a single call. It **closes the session once the command finishes** by default (the result is already in this call); `keep:true` leaves it in read-only retention instead. If it is still running at `timeoutSec` (1~600, default 120) it returns `running:true` and **does not kill the session** (whether to keep waiting or close it is the caller’s call). When to use this instead of the bash tool: when the user should **see** the command, or when it must run inside a terminal session; for purely non-interactive commands bash is more direct |
|
|
@@ -257,7 +274,9 @@ This is why “`tty_open` a command that finishes and read the result afterwards
|
|
|
257
274
|
|
|
258
275
|
### Shell integration (OSC 133/7, 0.4.0)
|
|
259
276
|
|
|
260
|
-
|
|
277
|
+
On POSIX, hooks are injected through the existing `-c` wrapper layer according to the shell type; on
|
|
278
|
+
Windows the PowerShell family gets a stable `-File` stub instead (see the Windows section above). Both are
|
|
279
|
+
transparent to the user and change no rc:
|
|
261
280
|
|
|
262
281
|
- **zsh**: `ZDOTDIR` points at a temporary stub directory (the same approach VS Code uses); the stub sources
|
|
263
282
|
the user’s original rc first and then appends `precmd`/`preexec` hooks;
|
|
@@ -279,8 +298,9 @@ buffer). The look-back lower bound is raised to “just after the last `B` marke
|
|
|
279
298
|
the echo sits between `A` and `B`, so text in the echo never counts as a hit (deliberately no text
|
|
280
299
|
comparison here: line wrapping / ANSI / multi-line paste would break it).
|
|
281
300
|
|
|
282
|
-
- **Environments without `B` markers** (integration off / local Windows tabs / a remote host without
|
|
283
|
-
hooks) have no boundary to cut at, so since D75 the echo is
|
|
301
|
+
- **Environments without `B` markers** (integration off / local Windows cmd tabs / a remote host without
|
|
302
|
+
the hooks / PSReadLine turned off by the user) have no boundary to cut at, so since D75 the echo is
|
|
303
|
+
excluded by a different test: the command
|
|
284
304
|
lines that the most recent `tty_send` submitted are stripped out of the candidate text and the pattern
|
|
285
305
|
is retried — only “no longer matches after stripping” counts as a pure echo. That removes the false
|
|
286
306
|
positive where the command never ran yet the wait reported `matched:true`, while the same text really
|
|
@@ -624,7 +644,14 @@ and the agent tools all reuse the same scheduling.
|
|
|
624
644
|
same name overwrites; an empty name uses the hostname); the ✎ on a “+” menu entry and the **edit** in the
|
|
625
645
|
settings card use the **same form** — three grouped sections (connection / authentication / options) plus
|
|
626
646
|
credential storage, the credential-reference picker, “test connection” and “File Browser”, renaming
|
|
627
|
-
supported and duplicate names rejected. The
|
|
647
|
+
supported and duplicate names rejected. The “Book name” row is **always visible** (0.31.0): typing a name
|
|
648
|
+
**automatically ticks** “save to connection book”, clearing it **automatically unticks**, and unticking by
|
|
649
|
+
hand clears the name too — what a click will save is always what the form shows. The dialog itself is a
|
|
650
|
+
**three-part shell** (0.31.0): the title
|
|
651
|
+
and the bottom action row are pinned and **only the middle scrolls**; the low-frequency items (jump host /
|
|
652
|
+
proxy command / host key alias) live in an “**Advanced**” disclosure that starts expanded when the entry
|
|
653
|
+
actually has them and collapsed otherwise (when collapsed, that row names what is configured — it is not a
|
|
654
|
+
black box). The only difference is **how it is submitted**: the menu dialog
|
|
628
655
|
(“save changes” / “connect (and save)”) writes through immediately, while the settings card commits into the
|
|
629
656
|
card's form with “apply” and persists with the card's “save”;
|
|
630
657
|
- **Authentication (auth), one of three**:
|
|
@@ -838,7 +865,7 @@ sub-page under the Plugins sidebar, and `≤0.1.5` uses the settings-page card.
|
|
|
838
865
|
| `reconnectGraceSec` | 120 | Seconds a session is kept alive after an abnormal disconnect (0~3600): the session survives a page refresh/network blip waiting for a reconnect, and the reaper ends it on timeout; `0` = the old behavior, end immediately on disconnect |
|
|
839
866
|
| `sshHosts` | `[]` | SSH connection book (selectable in the panel “+” menu): entries `{name, host, port=22, username, auth=agent\|key\|password, keyPath, passphrase, password, agentForward, hostKeyAlias='', persist=false}`; saved as a whole-set replacement, the same name overwrites; `password` / `passphrase` support `env:VAR` references so no plaintext is stored; with persistence on, clicking an entry opens a tmux persistent session by default, and `persist=false` is an **opt-out**; an empty `hostKeyAlias` locates fingerprints by host address (TOFU), while a non-empty one locates them by alias (several addresses of one host share a record — see “SSH connections”) |
|
|
840
867
|
| `hostKeys` | `[]` | SSH host key records (TOFU, maintained automatically): entries `{host, port, fingerprints[]}` (the legacy single `fingerprint` field is migrated and merged on read); unique by host:port, one record holds all of a host’s keys, appended automatically on the first connection, any matching fingerprint is allowed, and a full mismatch rejects the connection; the settings card can delete them to reset |
|
|
841
|
-
| `shellIntegration` | true | Injects the OSC 133/7 shell integration (command boundary markers + cwd reporting; `tty_capture{last}` depends on it); zsh/bash
|
|
868
|
+
| `shellIntegration` | true | Injects the OSC 133/7 shell integration (command boundary markers + cwd reporting; `tty_capture{last}` depends on it); zsh/bash on POSIX and the PowerShell family on Windows (`-File` stub), other shells (including Windows cmd) skipped automatically; can be turned off when compatibility problems appear |
|
|
842
869
|
| `tunnels` | `[]` | Port-forwarding tunnels: entries `{name, bookName, direction=local\|remote, localPort?, remoteHost?, remotePort?, localTargetHost?, localTargetPort?, enabled}`; `bookName` references a connection-book entry for host and authentication; maintained graphically in the “Port forwarding” block of the card |
|
|
843
870
|
| `sftpStyle` | `dialog` | SFTP File Browser UI style: `dialog` single pane (remote directory + upload/download/drag & drop) / `dual` two panes (local left / remote right, inline `⇨/⇦` server-side direct transfer); reopen SFTP for it to take effect |
|
|
844
871
|
| `persistence` | `off` | Session persistence: `off` sessions live and die with the host (default); `tmux` makes **every newly opened tab hosted by the tmux server by default**, recoverable across a host restart (requires tmux locally/remotely); the SSH dialog can opt out for a single connection |
|
|
@@ -1191,8 +1218,10 @@ verify things like “is there still a white panel after switching light/dark th
|
|
|
1191
1218
|
only for `reconnectGraceSec` (120s by default), and a host process restart ends all sessions; sessions not
|
|
1192
1219
|
reconnected before the deadline are ended by the reaper, and scroll history beyond the output buffer
|
|
1193
1220
|
(last 256KB) cannot be recovered.
|
|
1194
|
-
- **Shell integration
|
|
1195
|
-
reports a clear error rather than a wrong
|
|
1221
|
+
- **Shell integration covers zsh / bash on POSIX and the PowerShell family on Windows**: other shells
|
|
1222
|
+
(Windows cmd) are skipped automatically (`tty_capture{last}` reports a clear error rather than a wrong
|
|
1223
|
+
one); on PowerShell 7 the command output can land after the D marker, so `tty_capture{last}` may be empty
|
|
1224
|
+
there (read the tail with `tty_capture` instead). bash < 4.4 uses the DEBUG trap fallback: internal commands
|
|
1196
1225
|
of compound commands such as loops emit extra B markers, and `tty_capture{last}` captures only the output
|
|
1197
1226
|
after the last internal command for those commands (exit codes and `tty_expect` are unaffected). If the
|
|
1198
1227
|
user’s rc overrides `PROMPT_COMMAND`/the hook array, the integration may stop working — turn off
|
package/README.md
CHANGED
|
@@ -124,10 +124,18 @@ dsh plugin --profile web add link:$(pwd)/packages/tty # 仓库开发调试
|
|
|
124
124
|
下移一格、**不提交命令行**——`tty_send` 按工具描述发 `echo X\n` 时命令停在输入行上(没有输出、
|
|
125
125
|
没有新提示符,看起来像「发出去了但没执行」)。**win32 的本地会话**上插件现在把裸 LF 补成 CRLF
|
|
126
126
|
(已经是 CRLF 的不重复补;非 Windows 与 SSH 会话原样透传),所以照描述写 `\n` 这条主路径直接可用;
|
|
127
|
-
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
127
|
+
- **shell 集成(OSC 133/7)按家族分**:**PowerShell 家族支持**(`powershell.exe` / `pwsh.exe`)——
|
|
128
|
+
注入走 `-File` 稳定桩(挂 `prompt` + `PSConsoleHostReadLine` 钩子),拿到 `tty_list.cwd` 跟随
|
|
129
|
+
`cd`、退出码、`running` 三态与命令粒度的 `tty_expect`;**cmd 不支持**(没有命令开始/结束钩子),
|
|
130
|
+
设置卡片把开关置灰并指向「把 Shell 路径换成 PowerShell」。**已知限制**:PowerShell 7 上命令输出
|
|
131
|
+
在 ConPTY 里晚于 D 标记抵达(渲染重画是异步批量的,与 tmux 场景同根因),`tty_capture{last}`
|
|
132
|
+
可能取到空 —— 那里用 `tty_capture` 读尾部;Windows PowerShell 5.1 不受影响(两版都真机实测过)。
|
|
133
|
+
桩靠 `-ExecutionPolicy Bypass`(进程级)才载得进来,两条边界如实记着:**组策略**把执行策略锁成
|
|
134
|
+
Restricted / AllSigned 时该参数压不过 GPO,桩载不进去、标签照开而集成静默失效(与「用户关了
|
|
135
|
+
PSReadLine」同一种降级);这个参数还会把值写进 `$Env:PSExecutionPolicyPreference`,从该会话里
|
|
136
|
+
再起的 PowerShell 会继承它。另有一条已知副作用:包装 `prompt` 会让**用户原 prompt 读到的 `$?`**
|
|
137
|
+
变成我们那几次写入的成败(恒真),依赖 `$?` 的失败提示会失效;
|
|
138
|
+
- **不支持的两项(宿主侧自动关掉,设置卡片里写明原因)**:
|
|
131
139
|
- **tmux 持久化**:Windows 上没有 tmux,本地标签照常打开但不受托管(SSH 到 Linux 主机仍可用);
|
|
132
140
|
- **服务器状态条**:本地只拿得到 CPU / 内存 / 在线时长(`node:os`),磁盘 / TCP / 网速 / 温度
|
|
133
141
|
显示「无」(**远端** Windows 主机走 PowerShell 那一跳,见「服务器状态条」一节);
|
|
@@ -138,7 +146,11 @@ dsh plugin --profile web add link:$(pwd)/packages/tty # 仓库开发调试
|
|
|
138
146
|
- **端到端覆盖(0.19.0)**:`scripts/windows-smoke.mjs` 在 CI 的 windows-latest 上跑真实 `cmd.exe`
|
|
139
147
|
的 spawn → 输入回显 → kill → 重开,外加两条只在真机上成立的链路(W6:`tty_send` 的裸 LF 经归一化
|
|
140
148
|
后 conhost 真的执行了命令,D74;W7:`command` 型会话跑完退出后转只读保留、`tty_capture` 仍读得到
|
|
141
|
-
退出前的输出,D77
|
|
149
|
+
退出前的输出,D77)。**W8(PowerShell 的 OSC 133/7 档)在 CI 上照常跑**(2026-10-13 起):
|
|
150
|
+
它此前只在真机车道守,是因为「杀一个 ConPTY 会话」会踩 `0xC0000374`——根因(同一个 PTY 被原生
|
|
151
|
+
`kill()` 两次)已定位并修好,见 [DEFECTS.md](./DEFECTS.md) 的 **D100** 与
|
|
152
|
+
[ROADMAP.md](./ROADMAP.md) 的 2026-10-13 一节;本机找不到 PowerShell 时它会如实进 `SKIP` 一档
|
|
153
|
+
(分母扣掉、汇总行点名,不许装成 `12/12`)。它抓出并钉住了「强杀本地 PTY 会崩宿主」这类只在 Windows
|
|
142
154
|
出现的问题——node-pty 在 Windows 上不接受 signal,而它的 `_deferNoArgs` 会把这个异常推迟到
|
|
143
155
|
socket 回调里抛出,调用方的 try/catch 拦不住。
|
|
144
156
|
|
|
@@ -148,7 +160,7 @@ dsh plugin --profile web add link:$(pwd)/packages/tty # 仓库开发调试
|
|
|
148
160
|
|
|
149
161
|
| 工具 | 作用 |
|
|
150
162
|
| --- | --- |
|
|
151
|
-
| `tty_list` | 列出终端会话(sid / kind(local\|ssh)/ target / pid / **cwd 实时跟随 cd** / 活动时间;tmux 持久会话带 `persist` 标记;agent 自己开的带 `owner: 'agent'`)。**含进程已退出但仍在只读保留期内的会话**(`exited:true` + 退出码/信号,见下节);**`running` 说明这个会话有没有命令在跑**(true = 在跑,现在别往里发命令;false = 命令已结束;**省略 = 无法判断**——非持久 SSH / fish·csh / Windows
|
|
163
|
+
| `tty_list` | 列出终端会话(sid / kind(local\|ssh)/ target / pid / **cwd 实时跟随 cd** / 活动时间;tmux 持久会话带 `persist` 标记;agent 自己开的带 `owner: 'agent'`)。**含进程已退出但仍在只读保留期内的会话**(`exited:true` + 退出码/信号,见下节);**`running` 说明这个会话有没有命令在跑**(true = 在跑,现在别往里发命令;false = 命令已结束;**省略 = 无法判断**——非持久 SSH / fish·csh / Windows 的 cmd 没有 shell 集成标记,**不是**「没在跑」),同源的 `lastExitCode` / `lastExitAt` 是「上一条已完成命令」的退出码与结束时刻(0.23.0)。文本里三态写作 `[空闲]` / `[运行中——现在别往里发命令]` / `[命令状态未知——…]`;**「未知」还包含一种情形**:宿主**本次启动之后没见过该会话的标记**(典型是 tmux 持久会话在宿主重启前就停在提示符上)——对它发一个回车或跑一条命令,标记补上就变 `[空闲]`;而非持久 SSH / fish·csh / Windows 的 cmd 永远不会有标记,`[命令状态未知]` 是它们的常态 |
|
|
152
164
|
| `tty_open` | **自己开一个终端会话**(0.20.0):本地 shell,或 `command` 直接跑一条命令(dev server / watch;**按宿主 shell 的语法整段执行**——POSIX shell 上 `cd x && cmd`、`a; b`、多行脚本都可以;**Windows 的 cmd / PowerShell 则按它们自己的语法**,当前 shell 与语法每轮都写在 systemPrompt 的终端一行里;不受下面「命令标签单行 ≤2000」那条客户端约束,D78),`persistName` 可要 tmux 持久化。**开出来的会话出现在用户的终端面板里**(普通标签、用户可见可接管),不做隐形会话 |
|
|
153
165
|
| `tty_close` | 关掉一个由 `tty_open` 开的会话(0.20.0)。**只允许关 agent 自己开的**:用户在面板里开的标签会被拒绝——agent 不越权结束用户正在用的终端。对**已退出但仍只读保留着**的会话同样可用——那是它的释放入口(默认**保留到显式关闭**,不按时间释放) |
|
|
154
166
|
| `tty_run` | **一次性命令**(0.23.0):开一个会话跑 `command`,等它结束,直接返回尾部输出 + 退出码——把「`tty_open` → 等 → `tty_capture{last}` → `tty_close`」四步压成一次调用。默认**跑完即关**(结果已在本次调用返回),`keep:true` 则留在只读保留态;到 `timeoutSec`(1~600,默认 120)还没结束就返回 `running:true` 且**不杀会话**(继续等或关掉由调用方决定)。何时用它而不是 bash 工具:需要用户**看得见**这条命令、或要跑在终端会话里时用它,纯非交互命令用 bash 更直接 |
|
|
@@ -228,7 +240,8 @@ dsh plugin --profile web add link:$(pwd)/packages/tty # 仓库开发调试
|
|
|
228
240
|
|
|
229
241
|
### shell 集成(OSC 133/7,0.4.0)
|
|
230
242
|
|
|
231
|
-
|
|
243
|
+
POSIX 上经既有的 `-c` 包装层按 shell 类型注入钩子,Windows 上走 PowerShell 的 `-File` 稳定桩
|
|
244
|
+
(都对用户透明,不改 rc):
|
|
232
245
|
|
|
233
246
|
- **zsh**:`ZDOTDIR` 指向临时桩目录(VS Code 同款方案),桩文件先 source
|
|
234
247
|
用户原 rc 再追加 `precmd`/`preexec` 钩子;
|
|
@@ -240,17 +253,26 @@ spawn 时经既有的 `-c` 包装层按 shell 类型注入钩子(对用户透
|
|
|
240
253
|
副作用:循环体等复合命令的内部命令会多发 B 标记,仅影响
|
|
241
254
|
`tty_capture{last}` 对这类命令的截取起点,D/退出码与 `tty_expect` 不受影响;
|
|
242
255
|
PROMPT_COMMAND 挂钩兼容字符串与数组(bash 5.1+)两种形态;
|
|
256
|
+
- **PowerShell(Windows)**:`-File` 稳定桩(`<DSH_HOME|~/.dsh>/tty[/<profile>]/shell/powershell/bootstrap.ps1`,
|
|
257
|
+
纯 ASCII —— Windows PowerShell 5.1 按当前 ANSI 代码页读无 BOM 的 .ps1,一个非 ASCII 字节就炸解析),
|
|
258
|
+
包装 `prompt` 与 `PSConsoleHostReadLine`;用户 profile 照常生效(桩在 profile **之后**载入,拿到的就是
|
|
259
|
+
用户自己那个 prompt,包装后原样调用)。退出码口径:B 时刻快照 `$LASTEXITCODE`、D 时刻**变了**才报它
|
|
260
|
+
(原生命令),否则按 `$?` 报 0/1(cmdlet)——刻意**不清空** `$LASTEXITCODE`,免得用户紧接着的
|
|
261
|
+
`echo $LASTEXITCODE` 读到空值;代价是连续两次同码的非零原生命令,第二次降级报 1。
|
|
262
|
+
拿不到原 `PSConsoleHostReadLine`(用户关了 PSReadLine)时**一个标记都不发**:只发 A/7 会让宿主
|
|
263
|
+
报「没在跑」,比「无法判断」更危险(D77);
|
|
243
264
|
- 标记语义:`133;A` prompt 开始 / `133;B` 命令开始 / `133;D;<exit>` 命令
|
|
244
265
|
结束带退出码 / `OSC 7 file://…` cwd 上报(`tty_list.cwd` 跟随 `cd`,
|
|
245
266
|
SSH 会话则上报远程路径);
|
|
246
|
-
- 其他 shell
|
|
267
|
+
- 其他 shell(含 Windows 的 cmd)静默关闭;配置 `shellIntegration: false` 可整体关掉(逃生门)。
|
|
247
268
|
|
|
248
269
|
**回溯匹配与已读水位线(D72)**:`tty_expect` 会先回看**还没被读过**的输出(命令瞬间跑完时
|
|
249
270
|
要等的标记早就在缓冲区里了),回看的起点抬到「未读区内最后一个 `B` 标记之后」——回显落在 `A`
|
|
250
271
|
与 `B` 之间,所以回显里的字样不会被当成命中(这里刻意不做文本比对:折行 / ANSI / 多行粘贴
|
|
251
272
|
都会把它打碎)。
|
|
252
273
|
|
|
253
|
-
- **没有 `B` 标记的环境**(未开集成 / Windows
|
|
274
|
+
- **没有 `B` 标记的环境**(未开集成 / Windows 的 cmd 标签 / 远端未装集成 / 用户关了 PSReadLine)
|
|
275
|
+
没有边界可切,D75 起
|
|
254
276
|
改用另一条判据剔除回显:把**最近 `tty_send` 提交过的命令行**从候选文本里削掉再试一次,
|
|
255
277
|
只有「削掉后不再命中」才算纯回显——这样「命令没执行、等待却自称 matched」这条假阳性没了,
|
|
256
278
|
而回显之后真的跑出来的同一段文本照旧命中。等满超时且 pattern 只命中过回显时,结果带
|
|
@@ -538,7 +560,12 @@ tmux server(专用 socket `dsh-tty`,与用户自己的 tmux 完全隔离)
|
|
|
538
560
|
- **连接簿**:SSH 连接对话框勾选「保存到连接簿」即存为条目(同名覆盖,
|
|
539
561
|
名称留空用主机名);「+」菜单条目的 ✎ 与设置卡片里的 **编辑** 走的是**同一套表单**——
|
|
540
562
|
连接 / 认证 / 选项 三段分组 + 凭据存储 + 凭据引用选择器 + 试连 + 文件浏览,
|
|
541
|
-
|
|
563
|
+
支持改名、同名冲突校验。「连接簿名称」这一行**常显**(0.31.0):在名称框里**填了名字就自动
|
|
564
|
+
勾上**「保存到连接簿」、**清空就自动取消**、手动取消会把名字一起清掉——按下去会保存什么,
|
|
565
|
+
界面上始终对得上。对话框本身是**三段式外壳**(0.31.0):标题与底部动作行固定,
|
|
566
|
+
**只有中段滚动**;低频项(跳板机 / 代理命令 / 主机密钥别名)收在「**高级**」折叠区里——
|
|
567
|
+
条目里配过就默认展开、没配过就收起(收起时那一行会点名里面配了什么,不是暗盒)。
|
|
568
|
+
两者只差**提交方式**:菜单对话框是「保存修改 / 连接(并保存)」
|
|
542
569
|
立即落盘,设置卡片是「应用」进卡片表单、再随卡片「保存」写入配置;
|
|
543
570
|
- **认证方式(auth)三选一**:
|
|
544
571
|
- `agent`(默认)——走 ssh-agent(`SSH_AUTH_SOCK`),凭证不落盘,最推荐;
|