@hyzyn/dsh-tty 0.31.0 → 0.32.1
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 +38 -10
- package/client.js +29 -29
- package/lib/index.d.ts +69 -7
- package/lib/index.js +207 -23
- package/lib/index.js.map +1 -1
- package/lib/shell-integration.d.ts +10 -0
- package/lib/shell-integration.js +171 -9
- package/lib/shell-integration.js.map +1 -1
- package/package.json +1 -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/pwsh-probe.mjs +411 -0
- package/scripts/windows-smoke.mjs +97 -2
package/README.en.md
CHANGED
|
@@ -129,18 +129,36 @@ Both were reproduced on **Windows 11 ARM (24H2) + Node 22 ARM64**. The fix:
|
|
|
129
129
|
banner) but deliberately **not `-NoProfile`** — the user’s profile is where aliases and functions come from.
|
|
130
130
|
TERM / COLORTERM are meaningless for ConPTY and are no longer injected;
|
|
131
131
|
- **“Run one command” tabs** (docker exec, command tabs opened by the agent) use `cmd /c` or
|
|
132
|
-
`PowerShell -Command`;
|
|
132
|
+
`PowerShell -Command`; **PowerShell’s `-Command` collapses a non-zero last command into process exit code
|
|
133
|
+
1** (`cmd /c exit 5` → 1, both versions), so to get a concrete code let the command `exit 5` itself (POSIX
|
|
134
|
+
`sh -c` does not behave this way);
|
|
133
135
|
- **Input line-ending normalisation (D74, reported on real hardware 2026-09-27)**: conhost treats Enter as
|
|
134
136
|
**CR**, so a bare LF only moves the cursor down and **does not submit the command line** — `tty_send`
|
|
135
137
|
writing `echo X\n` as the tool description says leaves the command sitting on the input line (no output,
|
|
136
138
|
no new prompt, looking like “it was sent but never ran”). For **local sessions on win32** the plugin now
|
|
137
139
|
turns a bare LF into CRLF (an existing CRLF is not doubled; non-Windows and SSH sessions pass through
|
|
138
140
|
untouched), so the documented `\n` path just works;
|
|
139
|
-
- **
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
141
|
+
- **Shell integration (OSC 133/7) depends on the shell family**: the **PowerShell family is supported**
|
|
142
|
+
(`powershell.exe` / `pwsh.exe`) through a stable `-File` stub that hooks `prompt` and
|
|
143
|
+
`PSConsoleHostReadLine` — this yields cwd tracking (`tty_list.cwd` following `cd`), exit codes, the
|
|
144
|
+
`running` state and command-granular `tty_expect`. **cmd is not** (it has no command-boundary hooks), so
|
|
145
|
+
the settings card greys the switch out and points at “switch the shell path to PowerShell”. **The two
|
|
146
|
+
versions differ, and the syntax hint is branched by version**: `&&` / `||` are **PowerShell 7** only —
|
|
147
|
+
on 5.1 `&&` is a parse error and not a single command runs. **Known limit (not reproduced)**: it was
|
|
148
|
+
recorded that on PowerShell 7 the command output reaches ConPTY *after* the D marker, so
|
|
149
|
+
`tty_capture{last}` may come back empty; on 2026-10-13 this was re-measured on pwsh **7.6.6** (Win11
|
|
150
|
+
ARM64) across three output shapes (20 small outputs / a 2000-line burst / 20 writes over 2s) with
|
|
151
|
+
**0/20 empty windows** — not reproduced. If you do hit one, read the tail with `tty_capture` and report
|
|
152
|
+
the pwsh version. One more **exit-code rule**: in the PowerShell family a **parse error** (`&&` on 5.1,
|
|
153
|
+
`echo (1` on both) runs nothing at all yet the D marker reports **0** — never judge success by the exit
|
|
154
|
+
code alone; the error text is in the output. The stub only loads through `-ExecutionPolicy Bypass` (process-scoped); two boundaries
|
|
155
|
+
are recorded as they are: when **Group Policy** locks the execution policy to Restricted / AllSigned that
|
|
156
|
+
parameter does **not** override GPO, so the stub fails to load and the tab opens with integration silently
|
|
157
|
+
absent (the same degradation as “the user turned PSReadLine off”); the parameter also writes the value into
|
|
158
|
+
`$Env:PSExecutionPolicyPreference`, which PowerShell processes started from that session inherit. One more
|
|
159
|
+
known side effect: wrapping `prompt` makes **the user’s original prompt see its own `$?`** as the result of
|
|
160
|
+
our writes (always true), so failure indicators that rely on `$?` stop working;
|
|
161
|
+
- **Two things are not supported** (the host turns them off and the settings card explains why):
|
|
144
162
|
- **tmux persistence**: there is no tmux on Windows, so local tabs open normally but are not managed
|
|
145
163
|
(SSH into a Linux host still works);
|
|
146
164
|
- **Server status bar**: locally only CPU / memory / uptime are available (`node:os`); disk / TCP / network
|
|
@@ -154,7 +172,13 @@ Both were reproduced on **Windows 11 ARM (24H2) + Node 22 ARM64**. The fix:
|
|
|
154
172
|
- **End-to-end coverage (0.19.0)**: `scripts/windows-smoke.mjs` drives a real `cmd.exe` through
|
|
155
173
|
spawn → input echo → kill → respawn on the CI windows-latest runner, plus two links that only hold on
|
|
156
174
|
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).
|
|
175
|
+
session that exits turns into read-only retention and `tty_capture` still reads its pre-exit output, D77).
|
|
176
|
+
**W8 (the PowerShell OSC 133/7 stage) runs on CI** (since 2026-10-13): it used to be guarded by the
|
|
177
|
+
**real-machine lane** only, because killing a ConPTY session there tripped `0xC0000374` — the root cause
|
|
178
|
+
(the same PTY being natively `kill()`ed twice) is now located and fixed, see **D100** in
|
|
179
|
+
[DEFECTS.md](./DEFECTS.md) and the 2026-10-13 section of [ROADMAP.md](./ROADMAP.md). Where no PowerShell
|
|
180
|
+
exists the stage honestly reports its own `SKIP` row (excluded from the denominator, never dressed up as
|
|
181
|
+
`12/12`). It caught and now pins a
|
|
158
182
|
Windows-only failure class: force-killing a local PTY crashed the host — node-pty rejects signals
|
|
159
183
|
on Windows, and its `_deferNoArgs` re-throws that error from a socket callback, where the caller’s
|
|
160
184
|
try/catch cannot see it.
|
|
@@ -165,7 +189,7 @@ The plugin injects nineteen tools into the agent (operations show up live in the
|
|
|
165
189
|
|
|
166
190
|
| Tool | Purpose |
|
|
167
191
|
| --- | --- |
|
|
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
|
|
192
|
+
| `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
193
|
| `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
194
|
| `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
195
|
| `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 +281,9 @@ This is why “`tty_open` a command that finishes and read the result afterwards
|
|
|
257
281
|
|
|
258
282
|
### Shell integration (OSC 133/7, 0.4.0)
|
|
259
283
|
|
|
260
|
-
|
|
284
|
+
On POSIX, hooks are injected through the existing `-c` wrapper layer according to the shell type; on
|
|
285
|
+
Windows the PowerShell family gets a stable `-File` stub instead (see the Windows section above). Both are
|
|
286
|
+
transparent to the user and change no rc:
|
|
261
287
|
|
|
262
288
|
- **zsh**: `ZDOTDIR` points at a temporary stub directory (the same approach VS Code uses); the stub sources
|
|
263
289
|
the user’s original rc first and then appends `precmd`/`preexec` hooks;
|
|
@@ -279,8 +305,9 @@ buffer). The look-back lower bound is raised to “just after the last `B` marke
|
|
|
279
305
|
the echo sits between `A` and `B`, so text in the echo never counts as a hit (deliberately no text
|
|
280
306
|
comparison here: line wrapping / ANSI / multi-line paste would break it).
|
|
281
307
|
|
|
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
|
|
308
|
+
- **Environments without `B` markers** (integration off / local Windows cmd tabs / a remote host without
|
|
309
|
+
the hooks / PSReadLine turned off by the user) have no boundary to cut at, so since D75 the echo is
|
|
310
|
+
excluded by a different test: the command
|
|
284
311
|
lines that the most recent `tty_send` submitted are stripped out of the candidate text and the pattern
|
|
285
312
|
is retried — only “no longer matches after stripping” counts as a pure echo. That removes the false
|
|
286
313
|
positive where the command never ran yet the wait reported `matched:true`, while the same text really
|
|
@@ -845,7 +872,7 @@ sub-page under the Plugins sidebar, and `≤0.1.5` uses the settings-page card.
|
|
|
845
872
|
| `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 |
|
|
846
873
|
| `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”) |
|
|
847
874
|
| `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 |
|
|
848
|
-
| `shellIntegration` | true | Injects the OSC 133/7 shell integration (command boundary markers + cwd reporting; `tty_capture{last}` depends on it); zsh/bash
|
|
875
|
+
| `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 |
|
|
849
876
|
| `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 |
|
|
850
877
|
| `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 |
|
|
851
878
|
| `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 |
|
|
@@ -1198,8 +1225,10 @@ verify things like “is there still a white panel after switching light/dark th
|
|
|
1198
1225
|
only for `reconnectGraceSec` (120s by default), and a host process restart ends all sessions; sessions not
|
|
1199
1226
|
reconnected before the deadline are ended by the reaper, and scroll history beyond the output buffer
|
|
1200
1227
|
(last 256KB) cannot be recovered.
|
|
1201
|
-
- **Shell integration
|
|
1202
|
-
reports a clear error rather than a wrong
|
|
1228
|
+
- **Shell integration covers zsh / bash on POSIX and the PowerShell family on Windows**: other shells
|
|
1229
|
+
(Windows cmd) are skipped automatically (`tty_capture{last}` reports a clear error rather than a wrong
|
|
1230
|
+
one); a PowerShell 7 `tty_capture{last}` empty window was recorded but **not reproduced on pwsh 7.6.6**
|
|
1231
|
+
on 2026-10-13 (0/20 across three output shapes) — if you see one, read the tail with `tty_capture`. bash < 4.4 uses the DEBUG trap fallback: internal commands
|
|
1203
1232
|
of compound commands such as loops emit extra B markers, and `tty_capture{last}` captures only the output
|
|
1204
1233
|
after the last internal command for those commands (exit codes and `tty_expect` are unaffected). If the
|
|
1205
1234
|
user’s rc overrides `PROMPT_COMMAND`/the hook array, the integration may stop working — turn off
|
package/README.md
CHANGED
|
@@ -119,15 +119,29 @@ dsh plugin --profile web add link:$(pwd)/packages/tty # 仓库开发调试
|
|
|
119
119
|
**不补 `-NoProfile`** —— 用户的 profile 正是别名与函数的来源。TERM / COLORTERM 对 ConPTY
|
|
120
120
|
没有意义,也不再注入;
|
|
121
121
|
- **「跑一条命令」的标签**(docker exec、agent 起的命令标签)走 `cmd /c` 或
|
|
122
|
-
`PowerShell -Command
|
|
122
|
+
`PowerShell -Command`;**PowerShell 的 `-Command` 会把「末条命令非零」塌成进程退出码 1**
|
|
123
|
+
(`cmd /c exit 5` → 1,两版一致),要拿到具体码值就让命令自己 `exit 5`(POSIX 侧 `sh -c` 不会这样);
|
|
123
124
|
- **输入行尾归一化(D74,2026-09-27 真机报告)**:conhost 的 Enter 是 **CR**,裸 LF 只把光标
|
|
124
125
|
下移一格、**不提交命令行**——`tty_send` 按工具描述发 `echo X\n` 时命令停在输入行上(没有输出、
|
|
125
126
|
没有新提示符,看起来像「发出去了但没执行」)。**win32 的本地会话**上插件现在把裸 LF 补成 CRLF
|
|
126
127
|
(已经是 CRLF 的不重复补;非 Windows 与 SSH 会话原样透传),所以照描述写 `\n` 这条主路径直接可用;
|
|
127
|
-
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
128
|
+
- **shell 集成(OSC 133/7)按家族分**:**PowerShell 家族支持**(`powershell.exe` / `pwsh.exe`)——
|
|
129
|
+
注入走 `-File` 稳定桩(挂 `prompt` + `PSConsoleHostReadLine` 钩子),拿到 `tty_list.cwd` 跟随
|
|
130
|
+
`cd`、退出码、`running` 三态与命令粒度的 `tty_expect`;**cmd 不支持**(没有命令开始/结束钩子),
|
|
131
|
+
设置卡片把开关置灰并指向「把 Shell 路径换成 PowerShell」。**两版语法不同,提示文案按版本分支给**:
|
|
132
|
+
`&&` / `||` 只有 **PowerShell 7** 认,5.1 上写 `&&` 是解析错误(一条命令都不会跑)。
|
|
133
|
+
**已知限制(未复现)**:曾有记录说 PowerShell 7 上命令输出在 ConPTY 里晚于 D 标记抵达、
|
|
134
|
+
`tty_capture{last}` 可能取到空;2026-10-13 在 pwsh **7.6.6**(Win11 ARM64)上按三档输出量复测
|
|
135
|
+
(20 次小输出 / 2000 行大输出 / 2s 内分 20 次的慢输出)**0/20 空窗**,未复现 —— 真遇到就用
|
|
136
|
+
`tty_capture` 读尾部,并把当时的 pwsh 版本报回来。另有一条**退出码口径**:PowerShell 家族里
|
|
137
|
+
**解析错误**(5.1 上的 `&&`、两版上的 `echo (1`)命令一条都没跑,而 D 标记报 **0** —— 不能只看
|
|
138
|
+
退出码判成功,报错文本在输出里。
|
|
139
|
+
桩靠 `-ExecutionPolicy Bypass`(进程级)才载得进来,两条边界如实记着:**组策略**把执行策略锁成
|
|
140
|
+
Restricted / AllSigned 时该参数压不过 GPO,桩载不进去、标签照开而集成静默失效(与「用户关了
|
|
141
|
+
PSReadLine」同一种降级);这个参数还会把值写进 `$Env:PSExecutionPolicyPreference`,从该会话里
|
|
142
|
+
再起的 PowerShell 会继承它。另有一条已知副作用:包装 `prompt` 会让**用户原 prompt 读到的 `$?`**
|
|
143
|
+
变成我们那几次写入的成败(恒真),依赖 `$?` 的失败提示会失效;
|
|
144
|
+
- **不支持的两项(宿主侧自动关掉,设置卡片里写明原因)**:
|
|
131
145
|
- **tmux 持久化**:Windows 上没有 tmux,本地标签照常打开但不受托管(SSH 到 Linux 主机仍可用);
|
|
132
146
|
- **服务器状态条**:本地只拿得到 CPU / 内存 / 在线时长(`node:os`),磁盘 / TCP / 网速 / 温度
|
|
133
147
|
显示「无」(**远端** Windows 主机走 PowerShell 那一跳,见「服务器状态条」一节);
|
|
@@ -138,7 +152,11 @@ dsh plugin --profile web add link:$(pwd)/packages/tty # 仓库开发调试
|
|
|
138
152
|
- **端到端覆盖(0.19.0)**:`scripts/windows-smoke.mjs` 在 CI 的 windows-latest 上跑真实 `cmd.exe`
|
|
139
153
|
的 spawn → 输入回显 → kill → 重开,外加两条只在真机上成立的链路(W6:`tty_send` 的裸 LF 经归一化
|
|
140
154
|
后 conhost 真的执行了命令,D74;W7:`command` 型会话跑完退出后转只读保留、`tty_capture` 仍读得到
|
|
141
|
-
退出前的输出,D77
|
|
155
|
+
退出前的输出,D77)。**W8(PowerShell 的 OSC 133/7 档)在 CI 上照常跑**(2026-10-13 起):
|
|
156
|
+
它此前只在真机车道守,是因为「杀一个 ConPTY 会话」会踩 `0xC0000374`——根因(同一个 PTY 被原生
|
|
157
|
+
`kill()` 两次)已定位并修好,见 [DEFECTS.md](./DEFECTS.md) 的 **D100** 与
|
|
158
|
+
[ROADMAP.md](./ROADMAP.md) 的 2026-10-13 一节;本机找不到 PowerShell 时它会如实进 `SKIP` 一档
|
|
159
|
+
(分母扣掉、汇总行点名,不许装成 `12/12`)。它抓出并钉住了「强杀本地 PTY 会崩宿主」这类只在 Windows
|
|
142
160
|
出现的问题——node-pty 在 Windows 上不接受 signal,而它的 `_deferNoArgs` 会把这个异常推迟到
|
|
143
161
|
socket 回调里抛出,调用方的 try/catch 拦不住。
|
|
144
162
|
|
|
@@ -148,7 +166,7 @@ dsh plugin --profile web add link:$(pwd)/packages/tty # 仓库开发调试
|
|
|
148
166
|
|
|
149
167
|
| 工具 | 作用 |
|
|
150
168
|
| --- | --- |
|
|
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
|
|
169
|
+
| `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
170
|
| `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
171
|
| `tty_close` | 关掉一个由 `tty_open` 开的会话(0.20.0)。**只允许关 agent 自己开的**:用户在面板里开的标签会被拒绝——agent 不越权结束用户正在用的终端。对**已退出但仍只读保留着**的会话同样可用——那是它的释放入口(默认**保留到显式关闭**,不按时间释放) |
|
|
154
172
|
| `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 +246,8 @@ dsh plugin --profile web add link:$(pwd)/packages/tty # 仓库开发调试
|
|
|
228
246
|
|
|
229
247
|
### shell 集成(OSC 133/7,0.4.0)
|
|
230
248
|
|
|
231
|
-
|
|
249
|
+
POSIX 上经既有的 `-c` 包装层按 shell 类型注入钩子,Windows 上走 PowerShell 的 `-File` 稳定桩
|
|
250
|
+
(都对用户透明,不改 rc):
|
|
232
251
|
|
|
233
252
|
- **zsh**:`ZDOTDIR` 指向临时桩目录(VS Code 同款方案),桩文件先 source
|
|
234
253
|
用户原 rc 再追加 `precmd`/`preexec` 钩子;
|
|
@@ -240,17 +259,26 @@ spawn 时经既有的 `-c` 包装层按 shell 类型注入钩子(对用户透
|
|
|
240
259
|
副作用:循环体等复合命令的内部命令会多发 B 标记,仅影响
|
|
241
260
|
`tty_capture{last}` 对这类命令的截取起点,D/退出码与 `tty_expect` 不受影响;
|
|
242
261
|
PROMPT_COMMAND 挂钩兼容字符串与数组(bash 5.1+)两种形态;
|
|
262
|
+
- **PowerShell(Windows)**:`-File` 稳定桩(`<DSH_HOME|~/.dsh>/tty[/<profile>]/shell/powershell/bootstrap.ps1`,
|
|
263
|
+
纯 ASCII —— Windows PowerShell 5.1 按当前 ANSI 代码页读无 BOM 的 .ps1,一个非 ASCII 字节就炸解析),
|
|
264
|
+
包装 `prompt` 与 `PSConsoleHostReadLine`;用户 profile 照常生效(桩在 profile **之后**载入,拿到的就是
|
|
265
|
+
用户自己那个 prompt,包装后原样调用)。退出码口径:B 时刻快照 `$LASTEXITCODE`、D 时刻**变了**才报它
|
|
266
|
+
(原生命令),否则按 `$?` 报 0/1(cmdlet)——刻意**不清空** `$LASTEXITCODE`,免得用户紧接着的
|
|
267
|
+
`echo $LASTEXITCODE` 读到空值;代价是连续两次同码的非零原生命令,第二次降级报 1。
|
|
268
|
+
拿不到原 `PSConsoleHostReadLine`(用户关了 PSReadLine)时**一个标记都不发**:只发 A/7 会让宿主
|
|
269
|
+
报「没在跑」,比「无法判断」更危险(D77);
|
|
243
270
|
- 标记语义:`133;A` prompt 开始 / `133;B` 命令开始 / `133;D;<exit>` 命令
|
|
244
271
|
结束带退出码 / `OSC 7 file://…` cwd 上报(`tty_list.cwd` 跟随 `cd`,
|
|
245
272
|
SSH 会话则上报远程路径);
|
|
246
|
-
- 其他 shell
|
|
273
|
+
- 其他 shell(含 Windows 的 cmd)静默关闭;配置 `shellIntegration: false` 可整体关掉(逃生门)。
|
|
247
274
|
|
|
248
275
|
**回溯匹配与已读水位线(D72)**:`tty_expect` 会先回看**还没被读过**的输出(命令瞬间跑完时
|
|
249
276
|
要等的标记早就在缓冲区里了),回看的起点抬到「未读区内最后一个 `B` 标记之后」——回显落在 `A`
|
|
250
277
|
与 `B` 之间,所以回显里的字样不会被当成命中(这里刻意不做文本比对:折行 / ANSI / 多行粘贴
|
|
251
278
|
都会把它打碎)。
|
|
252
279
|
|
|
253
|
-
- **没有 `B` 标记的环境**(未开集成 / Windows
|
|
280
|
+
- **没有 `B` 标记的环境**(未开集成 / Windows 的 cmd 标签 / 远端未装集成 / 用户关了 PSReadLine)
|
|
281
|
+
没有边界可切,D75 起
|
|
254
282
|
改用另一条判据剔除回显:把**最近 `tty_send` 提交过的命令行**从候选文本里削掉再试一次,
|
|
255
283
|
只有「削掉后不再命中」才算纯回显——这样「命令没执行、等待却自称 matched」这条假阳性没了,
|
|
256
284
|
而回显之后真的跑出来的同一段文本照旧命中。等满超时且 pattern 只命中过回显时,结果带
|