@hyzyn/dsh-tty 0.32.0 → 0.32.2
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 +15 -8
- package/README.md +10 -4
- package/lib/index.d.ts +8 -0
- package/lib/index.js +98 -10
- package/lib/index.js.map +1 -1
- package/lib/shell-integration.js +28 -7
- package/lib/shell-integration.js.map +1 -1
- package/package.json +6 -3
- package/scripts/pwsh-probe.mjs +411 -0
package/README.en.md
CHANGED
|
@@ -129,7 +129,9 @@ 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,
|
|
@@ -140,11 +142,16 @@ Both were reproduced on **Windows 11 ARM (24H2) + Node 22 ARM64**. The fix:
|
|
|
140
142
|
(`powershell.exe` / `pwsh.exe`) through a stable `-File` stub that hooks `prompt` and
|
|
141
143
|
`PSConsoleHostReadLine` — this yields cwd tracking (`tty_list.cwd` following `cd`), exit codes, the
|
|
142
144
|
`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”. **
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
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
|
|
148
155
|
are recorded as they are: when **Group Policy** locks the execution policy to Restricted / AllSigned that
|
|
149
156
|
parameter does **not** override GPO, so the stub fails to load and the tab opens with integration silently
|
|
150
157
|
absent (the same degradation as “the user turned PSReadLine off”); the parameter also writes the value into
|
|
@@ -1220,8 +1227,8 @@ verify things like “is there still a white panel after switching light/dark th
|
|
|
1220
1227
|
(last 256KB) cannot be recovered.
|
|
1221
1228
|
- **Shell integration covers zsh / bash on POSIX and the PowerShell family on Windows**: other shells
|
|
1222
1229
|
(Windows cmd) are skipped automatically (`tty_capture{last}` reports a clear error rather than a wrong
|
|
1223
|
-
one);
|
|
1224
|
-
|
|
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
|
|
1225
1232
|
of compound commands such as loops emit extra B markers, and `tty_capture{last}` captures only the output
|
|
1226
1233
|
after the last internal command for those commands (exit codes and `tty_expect` are unaffected). If the
|
|
1227
1234
|
user’s rc overrides `PROMPT_COMMAND`/the hook array, the integration may stop working — turn off
|
package/README.md
CHANGED
|
@@ -119,7 +119,8 @@ 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
|
|
@@ -127,9 +128,14 @@ dsh plugin --profile web add link:$(pwd)/packages/tty # 仓库开发调试
|
|
|
127
128
|
- **shell 集成(OSC 133/7)按家族分**:**PowerShell 家族支持**(`powershell.exe` / `pwsh.exe`)——
|
|
128
129
|
注入走 `-File` 稳定桩(挂 `prompt` + `PSConsoleHostReadLine` 钩子),拿到 `tty_list.cwd` 跟随
|
|
129
130
|
`cd`、退出码、`running` 三态与命令粒度的 `tty_expect`;**cmd 不支持**(没有命令开始/结束钩子),
|
|
130
|
-
设置卡片把开关置灰并指向「把 Shell 路径换成 PowerShell
|
|
131
|
-
|
|
132
|
-
|
|
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
|
+
退出码判成功,报错文本在输出里。
|
|
133
139
|
桩靠 `-ExecutionPolicy Bypass`(进程级)才载得进来,两条边界如实记着:**组策略**把执行策略锁成
|
|
134
140
|
Restricted / AllSigned 时该参数压不过 GPO,桩载不进去、标签照开而集成静默失效(与「用户关了
|
|
135
141
|
PSReadLine」同一种降级);这个参数还会把值写进 `$Env:PSExecutionPolicyPreference`,从该会话里
|
package/lib/index.d.ts
CHANGED
|
@@ -540,6 +540,14 @@ interface ShellIntegrationState {
|
|
|
540
540
|
sawMark: boolean;
|
|
541
541
|
/** B..D 之间:命令输出捕获中。 */
|
|
542
542
|
inCommand: boolean;
|
|
543
|
+
/**
|
|
544
|
+
* 当前这条命令**开始的时刻**(见到那个 `B` 的 Date.now();0 = 还没见过 B)。
|
|
545
|
+
*
|
|
546
|
+
* 用途只有一个(D101):区分「命令行回显」与「往在跑的程序里敲的字」。命令行的回显是**在 B
|
|
547
|
+
* 之前**提交的那次 `tty_send`(`session.lastInputAt < commandStartedAt`),而 TUI 里的按键
|
|
548
|
+
* 一定晚于 B —— 后者在屏上出现是真实输出,不许当回显剔掉(D75 的边界)。
|
|
549
|
+
*/
|
|
550
|
+
commandStartedAt: number;
|
|
543
551
|
cmdBuffer: string;
|
|
544
552
|
/** T 标记带来的 pane 快照(tmux 持久标签;D 时优先于 cmdBuffer)。 */
|
|
545
553
|
pendingT: string | null;
|
package/lib/index.js
CHANGED
|
@@ -768,7 +768,7 @@ const FLUSH_INTERVAL_MS = 12;
|
|
|
768
768
|
/** 待发输出超过该字符数时跳过窗口立即冲刷(防超长输出无限延迟)。 */
|
|
769
769
|
const FLUSH_SIZE_CHARS = 64 * 1024;
|
|
770
770
|
function createShellState() {
|
|
771
|
-
return { carry: '', sawMark: false, inCommand: false, cmdBuffer: '', pendingT: null, lastCommand: null, cmdSeq: 0 };
|
|
771
|
+
return { carry: '', sawMark: false, inCommand: false, commandStartedAt: 0, cmdBuffer: '', pendingT: null, lastCommand: null, cmdSeq: 0 };
|
|
772
772
|
}
|
|
773
773
|
/** OSC 133;T 的 base64 payload → utf8 文本(无效输入返回 null)。 */
|
|
774
774
|
function decodeBase64Utf8(payload) {
|
|
@@ -842,6 +842,7 @@ export function feedShellIntegration(session, text) {
|
|
|
842
842
|
const kind = match[1];
|
|
843
843
|
if (kind === 'B') {
|
|
844
844
|
state.inCommand = true;
|
|
845
|
+
state.commandStartedAt = Date.now();
|
|
845
846
|
state.cmdBuffer = '';
|
|
846
847
|
state.pendingT = null;
|
|
847
848
|
}
|
|
@@ -1174,6 +1175,66 @@ function lastCommandStart(text) {
|
|
|
1174
1175
|
OSC133_RE.lastIndex = 0; // 归位:这个正则是共用的(feedShellIntegration 也用它)
|
|
1175
1176
|
return end;
|
|
1176
1177
|
}
|
|
1178
|
+
/**
|
|
1179
|
+
* 从原始流里取出**命令输出**的部分(D101):丢掉每个 `A`(prompt 开始)到其后第一个 `B`
|
|
1180
|
+
* (命令开始)之间的文本,以及末尾那段还没等到 `B` 的 `A` 段。
|
|
1181
|
+
*
|
|
1182
|
+
* 为什么需要它:`A..B` 之间只有提示符与**命令行回显**——真实输出一定在 `B` 之后。这是
|
|
1183
|
+
* shell 集成的硬边界(不是文本启发式)。回溯路径一直在用它(`lastCommandStart` 从最后一个
|
|
1184
|
+
* `B` 起切),而 live 路径此前拿**整段原始流**去匹配,于是「字面出现在命令行里」的 pattern
|
|
1185
|
+
* 会命中自己的回显、秒回 matched —— 命令其实还在跑(D75 的文本剔除在窗口里出现过任意 `B`
|
|
1186
|
+
* 标记时也不启用,见 `echoStrippable`)。
|
|
1187
|
+
*
|
|
1188
|
+
* 真机实测(2026-10-13,Windows 11 ARM64 + pwsh 7.6.6 / Win PowerShell 5.1.26100):命令
|
|
1189
|
+
* `Start-Sleep -Seconds 2; echo PROBE_ECHO_QQQ` + 等 `PROBE_ECHO_QQQ`,两版分别在 **432ms /
|
|
1190
|
+
* 446ms** 就返回 matched;macOS/zsh 上同类用例 **1ms**。修法即本函数:命中前先按边界裁掉
|
|
1191
|
+
* 提示符/回显段。
|
|
1192
|
+
*
|
|
1193
|
+
* 没有标记的会话(cmd、集成被关、TUI 全屏重画)原样返回——降级语义不变。
|
|
1194
|
+
*
|
|
1195
|
+
* 用在两处:`unreadRegion`(回溯窗口,从最后一个 `B` 起切之后再做一次)与
|
|
1196
|
+
* `liveOutputRegion` 的「窗口里没有 `B`」那一支。
|
|
1197
|
+
*/
|
|
1198
|
+
function commandOutputRegion(text) {
|
|
1199
|
+
let result = '';
|
|
1200
|
+
let cursor = 0;
|
|
1201
|
+
let inPrompt = false;
|
|
1202
|
+
OSC133_RE.lastIndex = 0;
|
|
1203
|
+
for (const match of text.matchAll(OSC133_RE)) {
|
|
1204
|
+
const index = match.index ?? 0;
|
|
1205
|
+
if (!inPrompt)
|
|
1206
|
+
result += text.slice(cursor, index);
|
|
1207
|
+
if (match[1] === 'A')
|
|
1208
|
+
inPrompt = true;
|
|
1209
|
+
else if (match[1] === 'B')
|
|
1210
|
+
inPrompt = false;
|
|
1211
|
+
cursor = index + match[0].length;
|
|
1212
|
+
}
|
|
1213
|
+
if (!inPrompt)
|
|
1214
|
+
result += text.slice(cursor);
|
|
1215
|
+
OSC133_RE.lastIndex = 0; // 归位:这个正则是共用的(feedShellIntegration 也用它)
|
|
1216
|
+
return result;
|
|
1217
|
+
}
|
|
1218
|
+
/**
|
|
1219
|
+
* `tty_expect` 的 live 窗口:从「本次等待期间到达的原始流」里取出**命令输出**(D101)。
|
|
1220
|
+
*
|
|
1221
|
+
* 三种现场分别处理,判据都是 shell 集成的边界,不做文本启发式:
|
|
1222
|
+
* 1. 窗口里有 `B`(命令在本次等待期间开始了)→ 只取最后一个 `B` 之后。**命令行回显在 `B` 之前**
|
|
1223
|
+
* (真机上回显与 `B` 常在同一 chunk 里、回显在前),所以这一步就把回显丢掉了;
|
|
1224
|
+
* 2. 窗口里没有 `B` 但 `inCommand`(`B` 早于注册)→ 整段都是那个命令的输出(TUI 全屏重画、
|
|
1225
|
+
* 长任务刷屏),原样返回;
|
|
1226
|
+
* 3. 都没有 → 没有集成(cmd / 集成被关)或正停在提示符上:此时可能只有提示符与回显,也可能
|
|
1227
|
+
* 是没人发命令时自己冒出来的后台输出 —— 只能交给 `commandOutputRegion` 裁掉「未闭合的
|
|
1228
|
+
* `A` 段」(提示符 + 正在回显的命令行),其余照旧返回(后台输出不能被误杀)。
|
|
1229
|
+
*/
|
|
1230
|
+
function liveOutputRegion(text, state) {
|
|
1231
|
+
const fromB = lastCommandStart(text);
|
|
1232
|
+
if (fromB !== -1)
|
|
1233
|
+
return text.slice(fromB);
|
|
1234
|
+
if (state.inCommand)
|
|
1235
|
+
return text;
|
|
1236
|
+
return commandOutputRegion(text);
|
|
1237
|
+
}
|
|
1177
1238
|
/** 首次被 agent 工具触达时把水位线落在当下——否则第一次回扫会把用户此前的历史输出当成「还没读过」。 */
|
|
1178
1239
|
function ensureReadMark(session) {
|
|
1179
1240
|
if (session.readSeq >= 0)
|
|
@@ -1200,7 +1261,9 @@ function unreadRegion(session) {
|
|
|
1200
1261
|
const bufferStart = session.outputSeq - session.buffer.length;
|
|
1201
1262
|
const text = session.buffer.slice(Math.max(0, session.readSeq - bufferStart));
|
|
1202
1263
|
const start = lastCommandStart(text);
|
|
1203
|
-
|
|
1264
|
+
// D101:从最后一个 B 起切只解决了「回显在 B 之前」那一半;这段里还可能有一段**还没等到 B**
|
|
1265
|
+
// 的 A 段(提示符 + 正在回显的命令行),同样要在匹配前裁掉。
|
|
1266
|
+
return commandOutputRegion(start === -1 ? text : text.slice(start));
|
|
1204
1267
|
}
|
|
1205
1268
|
/**
|
|
1206
1269
|
* pattern 匹配的统一入口(D72):先对含 ANSI 的原始流试(live 路径原语义),
|
|
@@ -1227,6 +1290,13 @@ function testPattern(re, text) {
|
|
|
1227
1290
|
* - 真实输出里也出现的标记照旧命中(不误杀);
|
|
1228
1291
|
* - 只在回显行**末尾**匹配才削(cmd 的回显与提示符同行,所以按行尾切);
|
|
1229
1292
|
* - 有 B 标记 / 命令正在跑(TUI 全屏重画里出现输入文本是正常输出)时不启用。
|
|
1293
|
+
*
|
|
1294
|
+
* **D101 补**:上面第三条让这条剔除在真实会话里几乎从不启用——窗口里出现**前一条命令**的
|
|
1295
|
+
* `B` 标记就是常态,「命令正在跑」更是常态。真机实测(2026-10-13):`Start-Sleep -Seconds 2;
|
|
1296
|
+
* echo MARK` + 等 `MARK`,Windows PowerShell 5.1 / 7 分别 446ms / 432ms 就 matched,macOS/zsh
|
|
1297
|
+
* 上 1ms。所以回显的**主防线**改成零启发式的 `commandOutputRegion`(按 `A..B` 边界裁,
|
|
1298
|
+
* `tty_expect` 的 live 路径与 `unreadRegion` 都走它);本函数退成没有标记那种壳(cmd /
|
|
1299
|
+
* 集成被关——那里没有边界可用,只能按提交过的输入做文本剔除)的兜底。
|
|
1230
1300
|
* ------------------------------------------------------------------ */
|
|
1231
1301
|
/** 回显候选的行数上限(最近几条提交的输入)与单行长度上限。 */
|
|
1232
1302
|
const ECHO_INPUT_CAP = 8;
|
|
@@ -1257,13 +1327,21 @@ function noteSubmittedInput(session, data) {
|
|
|
1257
1327
|
function echoStrippable(session, text) {
|
|
1258
1328
|
if (session.recentInputs.length === 0)
|
|
1259
1329
|
return false;
|
|
1330
|
+
/*
|
|
1331
|
+
* 命令正在跑时(D101 修正):启用与否**不能**只看 inCommand —— 真机现场是「命令已经被接受
|
|
1332
|
+
* (B 早于注册)、回显稍后才回到缓冲区」,那时精确命中命令行文本的就是回显(Windows
|
|
1333
|
+
* PowerShell 上 432ms 就 matched,而命令还在 Start-Sleep)。
|
|
1334
|
+
*
|
|
1335
|
+
* 判据换成「最近一次提交**早于本条命令的开始**」:那是命令行本身(回显就该剔掉);提交晚于
|
|
1336
|
+
* 命令开始的,是往在跑的程序里敲的键 —— 它在屏上出现属于**真实输出**,不许剔(D75 的边界)。
|
|
1337
|
+
*/
|
|
1260
1338
|
if (session.shellState.inCommand)
|
|
1261
|
-
return
|
|
1339
|
+
return session.lastInputAt < session.shellState.commandStartedAt;
|
|
1262
1340
|
return lastCommandStart(text) === -1;
|
|
1263
1341
|
}
|
|
1264
1342
|
/**
|
|
1265
1343
|
* 把回显候选行从文本里削掉(保行结构)。按**行尾**匹配:cmd 的回显与提示符同行
|
|
1266
|
-
* (`C:\>echo X
|
|
1344
|
+
* (`C:\>echo X`),所以只削后缀、保留提示符前缀。行尾空白与控制字节先归一。
|
|
1267
1345
|
*/
|
|
1268
1346
|
function stripEchoLines(text, echoes) {
|
|
1269
1347
|
if (echoes.length === 0)
|
|
@@ -1272,7 +1350,12 @@ function stripEchoLines(text, echoes) {
|
|
|
1272
1350
|
return text
|
|
1273
1351
|
.split('\n')
|
|
1274
1352
|
.map((line) => {
|
|
1275
|
-
|
|
1353
|
+
/*
|
|
1354
|
+
* 行尾的空白与**控制字节**都算噪音(D101 真机实测):zsh 在命令行后面紧跟着写
|
|
1355
|
+
* bracketed-paste 开关 `\e[?2004l`,不把它剥掉,「按行尾削」就永远削不掉那一行——
|
|
1356
|
+
* 于是回显被当成真输出(macOS/zsh 上实测 1ms 命中)。
|
|
1357
|
+
*/
|
|
1358
|
+
const trimmed = line.replace(/[\s\x00-\x1f\x7f]+$/, '');
|
|
1276
1359
|
for (const echo of sorted) {
|
|
1277
1360
|
if (trimmed.endsWith(echo))
|
|
1278
1361
|
return trimmed.slice(0, trimmed.length - echo.length);
|
|
@@ -1283,14 +1366,16 @@ function stripEchoLines(text, echoes) {
|
|
|
1283
1366
|
}
|
|
1284
1367
|
/**
|
|
1285
1368
|
* 命中是否**只**落在回显上(纯回显 → 不算命中)。
|
|
1286
|
-
*
|
|
1369
|
+
*
|
|
1370
|
+
* D101 起只看**清洗后**的文本:原来原始流与清洗文本各削一次、要求「两边都不再命中」才算回显,
|
|
1371
|
+
* 于是原始流里跟在命令行后面的转义序列(`\e[?2004l`、zle 的光标移动……)让 raw 变体削不干净、
|
|
1372
|
+
* 照样命中 → 整条判据失效。清洗后的文本才是「agent 真正看得到的那一份」(`tty_capture` 与
|
|
1373
|
+
* `tty_expect` 返回的也是它),按它判定既够用又不自相矛盾。
|
|
1287
1374
|
*/
|
|
1288
1375
|
function echoOnlyMatch(re, text, session) {
|
|
1289
1376
|
if (!echoStrippable(session, text))
|
|
1290
1377
|
return false;
|
|
1291
|
-
|
|
1292
|
-
const strippedClean = stripEchoLines(cleanAnsiTail(text), session.recentInputs);
|
|
1293
|
-
return !testPattern(re, stripped) && !testPattern(re, strippedClean);
|
|
1378
|
+
return !testPattern(re, stripEchoLines(cleanAnsiTail(text), session.recentInputs));
|
|
1294
1379
|
}
|
|
1295
1380
|
/** 宽松清洗一份 tunnels 输入;输入不是数组时返回 undefined(表示「未提供,保持原值」)。 */
|
|
1296
1381
|
function sanitizeTunnels(input) {
|
|
@@ -5614,7 +5699,10 @@ const plugin = definePlugin({
|
|
|
5614
5699
|
// 的收窄,闭包里就得再判一次 undefined。
|
|
5615
5700
|
const onData = (chunk) => {
|
|
5616
5701
|
acc = (acc + decoder.write(chunk)).slice(-64 * 1024);
|
|
5617
|
-
|
|
5702
|
+
// D101:先按 shell 集成的命令边界裁掉提示符/回显段(见 liveOutputRegion),
|
|
5703
|
+
// 再取 16KB 尾部窗口。反过来(先切 16KB 再裁)会切掉段首那个 B,回显又漏回窗口里。
|
|
5704
|
+
const region = liveOutputRegion(acc, state);
|
|
5705
|
+
const hay = region.length > 16 * 1024 ? region.slice(-16 * 1024) : region;
|
|
5618
5706
|
if (testPattern(re, hay)) {
|
|
5619
5707
|
// D75:命中的若**只是刚送进去那行命令的回显**,不算命中——继续等真输出
|
|
5620
5708
|
if (echoOnlyMatch(re, hay, session))
|