@hyzyn/dsh-tty 0.22.0-rc.1 → 0.22.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.
@@ -34,6 +34,17 @@ export declare function defaultShellPath(platform?: NodeJS.Platform, env?: NodeJ
34
34
  * `C:\Program Files\PowerShell\7\pwsh.exe` 会整串返回(没有 `/`),判定就漏了。
35
35
  * 两个分隔符一起切,任何平台上都对。
36
36
  */
37
+ /**
38
+ * 本地「跑一条命令」时,**命令由哪个 shell 执行、按什么语法**(D78 补,2026-09-27 复核报告)。
39
+ *
40
+ * 为什么需要它:`command` 是整段交给宿主 shell 的(POSIX 分支 `exec <shell> -c`,Windows 分支
41
+ * `cmd /c` / `-Command` / `bash -c`),也就是**语法随宿主平台与「Shell 路径」设置变**。
42
+ * 只写「按整段 shell 代码执行、`a; b` 都可以」会误导模型:在 Windows 的 cmd 上,`;`、`for …; do`、
43
+ * `$?`、`$$`、单引号全都不是 cmd 语法——报告方就是在 Windows 上按 POSIX 语法复测,9 条全红。
44
+ *
45
+ * 文案要短(进 systemPrompt 每轮都出现),但必须点明「哪些不是这个 shell 的语法」。
46
+ */
47
+ export declare function commandShellHint(shell: string, platform?: NodeJS.Platform): string;
37
48
  export declare function isPowerShellShell(shell: string): boolean;
38
49
  export declare function buildShellSpawn(shell: string, term: string, colorTerm: string, integration: boolean, platform?: NodeJS.Platform): ShellSpawnPlan;
39
50
  /** POSIX 单引号安全包裹(路径/值进 inner.sh 与 -c 包装层用)。 */
@@ -274,7 +274,31 @@ export function buildCommandSpawn(shell, term, colorTerm, command, platform = pr
274
274
  if (platform === 'win32')
275
275
  return buildWindowsCommandSpawn(shell, command);
276
276
  const pre = `export TERM='${term}'; export COLORTERM='${colorTerm}';`;
277
- return { argv: [shell, '-c', `${pre} exec ${command}`], env: {} };
277
+ /*
278
+ * D78:命令**整体**交给内层 shell(`-c`),不再直接缀在 `exec` 后面。
279
+ *
280
+ * 旧写法是 `${pre} exec ${command}`,而 `exec` 只是**简单命令**的前缀:zsh 会把
281
+ * `exec echo A; echo B` 解析成 `[exec echo A] ; [echo B]`,第一条把 shell 进程替换
282
+ * 掉之后 `echo B` 永远不会被调度;`cd x && cmd` 的右支同理;`exec for …` 直接在
283
+ * 解析阶段报错;退出码也变成被 exec 的那条命令的。更狠的是内建命令:`exec cd /tmp`
284
+ * 在 zsh 里的语义是「跑完内建即结束当前 shell」,于是连第一条的输出都没有、
285
+ * `&&` 右支连同外层 shell 一起消失(`tty_open command="cd /tmp && pwd"` 实测空输出、
286
+ * rc=0,2026-09-27 报告)。
287
+ *
288
+ * 用户的命令是**一段 shell 代码**,不是一条 argv——这是「跑一条命令」这个工具的
289
+ * 基本契约:`cd dir && cmd`、`cmd; echo rc=$?` 正是 agent 最惯用的写法,静默少跑
290
+ * 后半段比报错更难查。内层仍用同一个 shell(交互习惯一致:zsh 的 `for` 语法照旧),
291
+ * 且不加 `-l/-i`(维持非交互语义,不 source rc,与旧路径一致)。
292
+ *
293
+ * 外层 `exec` 保留:进程被内层 shell 替换,「进程即命令」的语义不变——退出码取自
294
+ * 命令列表最后一条,**被信号打死时仍如实报 signal**(不套 exec 的话外层 shell 会把
295
+ * 信号退化成 128+n 的退出码,而 D77 的面板与工具文案正是靠 signal 区分崩溃与正常退出)。
296
+ *
297
+ * 内层用 `shSingleQuote` 包住:命令里的单引号由 `'\''` 转义,带引号 / 多行的命令
298
+ * 都能安全穿过外层 shell 的解析。
299
+ */
300
+ const inner = `${shSingleQuote(shell)} -c ${shSingleQuote(command)}`;
301
+ return { argv: [shell, '-c', `${pre} exec ${inner}`], env: {} };
278
302
  }
279
303
  /**
280
304
  * 本地终端默认 shell。
@@ -297,6 +321,33 @@ export function defaultShellPath(platform = process.platform, env = process.env)
297
321
  * `C:\Program Files\PowerShell\7\pwsh.exe` 会整串返回(没有 `/`),判定就漏了。
298
322
  * 两个分隔符一起切,任何平台上都对。
299
323
  */
324
+ /**
325
+ * 本地「跑一条命令」时,**命令由哪个 shell 执行、按什么语法**(D78 补,2026-09-27 复核报告)。
326
+ *
327
+ * 为什么需要它:`command` 是整段交给宿主 shell 的(POSIX 分支 `exec <shell> -c`,Windows 分支
328
+ * `cmd /c` / `-Command` / `bash -c`),也就是**语法随宿主平台与「Shell 路径」设置变**。
329
+ * 只写「按整段 shell 代码执行、`a; b` 都可以」会误导模型:在 Windows 的 cmd 上,`;`、`for …; do`、
330
+ * `$?`、`$$`、单引号全都不是 cmd 语法——报告方就是在 Windows 上按 POSIX 语法复测,9 条全红。
331
+ *
332
+ * 文案要短(进 systemPrompt 每轮都出现),但必须点明「哪些不是这个 shell 的语法」。
333
+ */
334
+ export function commandShellHint(shell, platform = process.platform) {
335
+ const name = shell.trim() === '' ? '(未配置)' : shell.trim();
336
+ if (platform !== 'win32') {
337
+ return `本地命令由 ${name} 执行:按 POSIX shell 语法(\`a; b\`、\`cd x && y\`、\`for …; do …; done\`、管道、单引号)`;
338
+ }
339
+ if (isPowerShellShell(name)) {
340
+ return `本地命令由 ${name} 执行:按 **PowerShell** 语法(\`;\` 分隔语句、\`$env:VAR\` 取环境变量、\`$(…)\` 子表达式;POSIX 的 \`&&\`、\`$?\`、单引号不是 PowerShell 5.1 的语法)`;
341
+ }
342
+ const kind = name.split(/[\\/]/).pop()?.toLowerCase() ?? '';
343
+ if (kind === 'bash.exe' || kind === 'bash' || kind === 'sh.exe' || kind === 'sh' || kind === 'zsh.exe' || kind === 'zsh') {
344
+ return `本地命令由 ${name} 执行:这是 POSIX shell,按 POSIX 语法(\`a; b\`、\`cd x && y\`、\`for …; do …; done\`)`;
345
+ }
346
+ if (kind === 'wsl.exe' || kind === 'wsl') {
347
+ return `本地命令由 ${name} 执行:命令经默认发行版的 \`sh -c\`,按 POSIX 语法`;
348
+ }
349
+ return `本地命令由 ${name} 执行:按 **cmd** 语法(\`&\` 顺序执行、\`&&\` 条件执行、\`|\` 管道、\`%VAR%\` 取环境变量;POSIX 的 \`;\`、\`for …; do\`、\`$?\`、\`$$\`、单引号都不是 cmd 语法)`;
350
+ }
300
351
  export function isPowerShellShell(shell) {
301
352
  const kind = shell.split(/[\\/]/).pop()?.toLowerCase() ?? '';
302
353
  return kind === 'powershell' || kind === 'powershell.exe' || kind === 'pwsh' || kind === 'pwsh.exe';
@@ -1 +1 @@
1
- {"version":3,"file":"shell-integration.js","sourceRoot":"","sources":["../src/shell-integration.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"shell-integration.js","sourceRoot":"","sources":["../src/shell-integration.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAC5E,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAA;AACxC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAQnD,gDAAgD;AAChD,MAAM,UAAU,gBAAgB;IAC9B,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,KAAK,CAAC,CAAA;AAC/B,CAAC;AAED,8DAA8D;AAC9D,SAAS,cAAc,CAAC,IAAY,EAAE,OAAe;IACnD,IAAI,CAAC;QACH,IAAI,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,KAAK,OAAO;YAAE,OAAM;IACpD,CAAC;IAAC,MAAM,CAAC;QACP,cAAc;IAChB,CAAC;IACD,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAC7C,MAAM,GAAG,GAAG,GAAG,IAAI,IAAI,OAAO,CAAC,GAAG,MAAM,CAAA;IACxC,aAAa,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;IAC3B,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;AACvB,CAAC;AAED;;;;;;;GAOG;AAEH,+CAA+C;AAC/C,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAkB,CAAA;AAE1C,MAAM,SAAS,GAAG;IAChB,EAAE;IACF,qCAAqC;IACrC,yCAAyC;IACzC,iCAAiC;IACjC,iCAAiC;IACjC,yDAAyD;IACzD,6DAA6D;IAC7D,2BAA2B;IAC3B,uDAAuD;IACvD,uDAAuD;IACvD,0DAA0D;IAC1D,iEAAiE;IACjE,0DAA0D;IAC1D,QAAQ;IACR,oCAAoC;IACpC,oCAAoC;IACpC,uCAAuC;IACvC,8CAA8C;IAC9C,MAAM;IACN,oDAAoD;IACpD,iDAAiD;IACjD,wDAAwD;IACxD,wCAAwC;IACxC,yBAAyB;IACzB,gCAAgC;IAChC,iGAAiG;IACjG,6CAA6C;IAC7C,qGAAqG;IACrG,QAAQ;IACR,KAAK;IACL,wBAAwB;IACxB,iBAAiB;IACjB,qCAAqC;IACrC,2CAA2C;IAC3C,+DAA+D;IAC/D,+BAA+B;IAC/B,oDAAoD;IACpD,KAAK;IACL,yBAAyB;IACzB,wBAAwB;IACxB,+BAA+B;IAC/B,KAAK;IACL,0CAA0C;IAC1C,oCAAoC;IACpC,gEAAgE;IAChE,mEAAmE;IACnE,IAAI;IACJ,qCAAqC;IACrC,EAAE;CACH,CAAA;AAED,MAAM,YAAY,GAAG;IACnB,EAAE;IACF,qCAAqC;IACrC,yCAAyC;IACzC,iCAAiC;IACjC,sBAAsB;IACtB,iDAAiD;IACjD,2BAA2B;IAC3B,uDAAuD;IACvD,uDAAuD;IACvD,0DAA0D;IAC1D,iEAAiE;IACjE,0DAA0D;IAC1D,QAAQ;IACR,oCAAoC;IACpC,oCAAoC;IACpC,uCAAuC;IACvC,8CAA8C;IAC9C,MAAM;IACN,wEAAwE;IACxE,yBAAyB;IACzB,gCAAgC;IAChC,iGAAiG;IACjG,6CAA6C;IAC7C,qGAAqG;IACrG,QAAQ;IACR,KAAK;IACL,wBAAwB;IACxB,iBAAiB;IACjB,8DAA8D;IAC9D,gEAAgE;IAChE,4DAA4D;IAC5D,yDAAyD;IACzD,2BAA2B;IAC3B,yCAAyC;IACzC,yDAAyD;IACzD,+BAA+B;IAC/B,wDAAwD;IACxD,KAAK;CACN,CAAA;AAED,MAAM,aAAa,GAAG;IACpB,IAAI;IACJ,qCAAqC;IACrC,EAAE;CACH,CAAA;AAED,SAAS,gBAAgB;IACvB,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;IAClC,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,MAAM,CAAA;IACvC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,gBAAgB,EAAE,EAAE,OAAO,EAAE,KAAK,CAAC,CAAA;QACpD,sDAAsD;QACtD,yCAAyC;QACzC,qDAAqD;QACrD,uCAAuC;QACvC,KAAK,MAAM,IAAI,IAAI,CAAC,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,CAAU,EAAE,CAAC;YAC5E,cAAc,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE;gBAC9B,uDAAuD;gBACvD,8BAA8B,GAAG,IAAI,GAAG,uCAAuC,GAAG,IAAI,GAAG,GAAG;gBAC5F,EAAE;aACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;QACf,CAAC;QACD,cAAc,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,EAAE;YAClC,uEAAuE;YACvE,gFAAgF;YAChF,GAAG,SAAS;SACb,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;QACb,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;QACxB,OAAO,GAAG,CAAA;IACZ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB;IACvB,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;IACnC,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,MAAM,CAAA;IACvC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,gBAAgB,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,CAAA;QACrD,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAA;QAC9B,cAAc,CAAC,EAAE,EAAE;YACjB,uEAAuE;YACvE,kDAAkD;YAClD,GAAG,YAAY;YACf,mCAAmC;YACnC,uCAAuC;YACvC,8EAA8E;YAC9E,8GAA8G;YAC9G,sCAAsC;YACtC,wBAAwB;YACxB,qBAAqB;YACrB,0CAA0C;YAC1C,UAAU;YACV,kDAAkD;YAClD,0CAA0C;YAC1C,2CAA2C;YAC3C,wDAAwD;YACxD,sBAAsB;YACtB,wCAAwC;YACxC,kCAAkC;YAClC,4EAA4E;YAC5E,iBAAiB;YACjB,UAAU;YACV,uCAAuC;YACvC,kCAAkC;YAClC,sFAAsF;YACtF,iBAAiB;YACjB,UAAU;YACV,QAAQ;YACR,mEAAmE;YACnE,qDAAqD;YACrD,gEAAgE;YAChE,sDAAsD;YACtD,kDAAkD;YAClD,+DAA+D;YAC/D,yCAAyC;YACzC,mDAAmD;YACnD,2BAA2B;YAC3B,+BAA+B;YAC/B,4DAA4D;YAC5D,YAAY;YACZ,0BAA0B;YAC1B,iCAAiC;YACjC,oBAAoB;YACpB,OAAO;YACP,6DAA6D;YAC7D,4DAA4D;YAC5D,sDAAsD;YACtD,mCAAmC;YACnC,8BAA8B;YAC9B,mGAAmG;YACnG,UAAU;YACV,MAAM;YACN,GAAG,aAAa;SACjB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;QACb,QAAQ,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;QACxB,OAAO,EAAE,CAAA;IACX,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAa,EAAE,IAAY,EAAE,SAAiB,EAAE,OAAe,EAAE,WAA4B,OAAO,CAAC,QAAQ;IAC7I,IAAI,QAAQ,KAAK,OAAO;QAAE,OAAO,wBAAwB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA;IACzE,MAAM,GAAG,GAAG,gBAAgB,IAAI,wBAAwB,SAAS,IAAI,CAAA;IACrE;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,MAAM,KAAK,GAAG,GAAG,aAAa,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,OAAO,CAAC,EAAE,CAAA;IACpE,OAAO,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,GAAG,SAAS,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,CAAA;AACjE,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,gBAAgB,CAAC,WAA4B,OAAO,CAAC,QAAQ,EAAE,MAAyB,OAAO,CAAC,GAAG;IACjH,IAAI,QAAQ,KAAK,OAAO;QAAE,OAAO,GAAG,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,SAAS,CAAA;IACjE,OAAO,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,UAAU,CAAA;AACxC,CAAC;AAED;;;;;;GAMG;AACH;;;;;;;;;GASG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAa,EAAE,WAA4B,OAAO,CAAC,QAAQ;IAC1F,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAA;IACzD,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;QACzB,OAAO,SAAS,IAAI,2EAA2E,CAAA;IACjG,CAAC;IACD,IAAI,iBAAiB,CAAC,IAAI,CAAC,EAAE,CAAC;QAC5B,OAAO,SAAS,IAAI,qHAAqH,CAAA;IAC3I,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,CAAA;IAC3D,IAAI,IAAI,KAAK,UAAU,IAAI,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;QACzH,OAAO,SAAS,IAAI,6EAA6E,CAAA;IACnG,CAAC;IACD,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;QACzC,OAAO,SAAS,IAAI,oCAAoC,CAAA;IAC1D,CAAC;IACD,OAAO,SAAS,IAAI,2HAA2H,CAAA;AACjJ,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,KAAa;IAC7C,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,CAAA;IAC5D,OAAO,IAAI,KAAK,YAAY,IAAI,IAAI,KAAK,gBAAgB,IAAI,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,UAAU,CAAA;AACrG,CAAC;AAED;;;;;;;;;;;GAWG;AACH,SAAS,sBAAsB,CAAC,KAAa;IAC3C,OAAO,EAAE,IAAI,EAAE,iBAAiB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,CAAA;AACnF,CAAC;AAED,6EAA6E;AAC7E,SAAS,wBAAwB,CAAC,KAAa,EAAE,OAAe;IAC9D,IAAI,iBAAiB,CAAC,KAAK,CAAC,EAAE,CAAC;QAC7B,OAAO,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,CAAA;IACnE,CAAC;IACD,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,CAAA;IAC5D,8BAA8B;IAC9B,IAAI,IAAI,KAAK,UAAU,IAAI,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;QACzH,OAAO,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,CAAA;IAClD,CAAC;IACD,kDAAkD;IAClD,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;QACzC,OAAO,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,CAAA;IAC9D,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,CAAA;AAClD,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAAa,EAAE,IAAY,EAAE,SAAiB,EAAE,WAAoB,EAAE,WAA4B,OAAO,CAAC,QAAQ;IAChJ,IAAI,QAAQ,KAAK,OAAO;QAAE,OAAO,sBAAsB,CAAC,KAAK,CAAC,CAAA;IAC9D,MAAM,GAAG,GAAG,gBAAgB,IAAI,wBAAwB,SAAS,IAAI,CAAA;IACrE,MAAM,IAAI,GAAG,SAAS,KAAK,GAAG,CAAA;IAC9B,IAAI,WAAW,EAAE,CAAC;QAChB,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;QAC5B,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;YACnB,MAAM,OAAO,GAAG,gBAAgB,EAAE,CAAA;YAClC,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;gBAC1B,OAAO;oBACL,IAAI,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,GAAG,6CAA6C,OAAO,EAAE,uBAAuB,OAAO,MAAM,IAAI,EAAE,CAAC;oBAC3H,GAAG,EAAE,EAAE;iBACR,CAAA;YACH,CAAC;QACH,CAAC;aAAM,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;YAC3B,MAAM,MAAM,GAAG,gBAAgB,EAAE,CAAA;YACjC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;gBACzB,OAAO;oBACL,IAAI,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,GAAG,IAAI,IAAI,cAAc,MAAM,GAAG,CAAC;oBAC1D,GAAG,EAAE,EAAE;iBACR,CAAA;YACH,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,CAAA;AAC3D,CAAC;AAED;;wEAEwE;AAExE,+CAA+C;AAC/C,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,OAAO,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,GAAG,CAAA;AACjD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CAAC,KAAa,EAAE,SAAiB,EAAE,WAAoB;IAC3F,MAAM,KAAK,GAAG;QACZ,WAAW;QACX,uDAAuD;QACvD,oBAAoB,aAAa,CAAC,SAAS,CAAC,EAAE;KAC/C,CAAA;IACD,IAAI,WAAW,EAAE,CAAC;QAChB,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;QAC5B,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;YACnB,MAAM,OAAO,GAAG,gBAAgB,EAAE,CAAA;YAClC,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;gBAC1B,KAAK,CAAC,IAAI,CACR,kDAAkD,EAClD,kBAAkB,aAAa,CAAC,OAAO,CAAC,EAAE,EAC1C,QAAQ,aAAa,CAAC,KAAK,CAAC,EAAE,CAC/B,CAAA;gBACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;YAChC,CAAC;QACH,CAAC;aAAM,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;YAC3B,MAAM,MAAM,GAAG,gBAAgB,EAAE,CAAA;YACjC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;gBACzB,KAAK,CAAC,IAAI,CAAC,QAAQ,aAAa,CAAC,KAAK,CAAC,aAAa,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;gBAC5E,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;YAChC,CAAC;QACH,CAAC;IACH,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,QAAQ,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;IAC1C,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;AAChC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hyzyn/dsh-tty",
3
- "version": "0.22.0-rc.1",
3
+ "version": "0.22.0",
4
4
  "description": "DSH Web GUI 的终端面板插件:侧边栏「终端」大弹窗,xterm.js + PTY 全交互终端(路线1),ssh2 原生 SSH 远程连接(方案 C),tmux 会话持久化(0.10.0),连接栏扩展点 ttyConnbar(0.13.0)、终端服务 ttyTerminal(0.14.0 open / 0.15.0 mount 就地嵌入)、面板内挂载位 ttyPanel(0.16.0 右侧 dock)、服务器状态条(0.17.0:按标签可见性采端主机 CPU / 内存 / 磁盘 / 在线时长 / TCP / 网速 / 温度,SSH 走同连接的非 PTY exec channel、本地走 os/proc,best-effort、不碰 PTY 流)、连接密码存入官方凭据存储(0.18.0:字段里只留 env: 引用、引用名按资源身份派生、候选来自凭据存储 ∪ 连接簿;设置卡片的连接编辑与连接对话框共用同一套表单)、Windows 宿主支持(0.18.1:默认 shell = %COMSPEC%、不做 POSIX 包装层、PowerShell 走 -NoLogo/-Command;shell 集成 / tmux / 状态条三项在 Windows 本地不适用,README 有完整边界)。",
5
5
  "keywords": [
6
6
  "dsh",
@@ -46,7 +46,7 @@
46
46
  },
47
47
  "dependencies": {
48
48
  "@deepseek-ai/schemastery": "^3.18.4",
49
- "@hyzyn/dsh-kit": "0.5.0-rc.1",
49
+ "@hyzyn/dsh-kit": "0.5.0",
50
50
  "@xterm/headless": "^5.5.0",
51
51
  "ssh2": "^1.17.0",
52
52
  "ws": "^8.18.0"
@@ -38,6 +38,9 @@
38
38
  * (不新建 PTY / 不占名额)、输出扇出、kill 广播 exit
39
39
  * B29. 禁用热生效(enabled 开关):工具/公告撤下与恢复、数据路由 403、
40
40
  * /config 保持可读写、存量 WS 被关闭与新升级被拒
41
+ * B34. 退出后的只读保留(D77):命令跑完仍可读、写被拒、tty_close 释放
42
+ * B35. `tty_open command=` 执行整段 shell 代码(D78):`a; b` / `cd x && cmd` /
43
+ * `for` 不被 exec 截断,退出码取自最后一条
41
44
  *
42
45
  * 用法:pnpm --filter @hyzyn/dsh-tty integration
43
46
  * 退出码:0 = 全部 PASS,1 = 任一 FAIL。
@@ -1896,12 +1899,140 @@ async function run() {
1896
1899
  }
1897
1900
  }
1898
1901
 
1902
+ // B34: 退出后的只读保留(D77,用户上报 issue #4 的正题)
1903
+ //
1904
+ // 现场:`tty_open` 跑一条**会结束**的命令,跑完会话就退役——输出还在终端上,
1905
+ // AI 一个字符都取不回来(用户被迫先开 `/bin/sh` 再往里塞命令)。这一条用真 PTY
1906
+ // 走一遍修好之后的链路:命令跑完 → 清单里仍有它(exited)→ tty_capture 读得到
1907
+ // 输出 → tty_send 拒写 → tty_close 释放。
1908
+ console.log('\n[31] 退出后的只读保留(D77)')
1909
+ {
1910
+ const open77 = toolDefs.find((d) => d.name === 'tty_open')
1911
+ const close77 = toolDefs.find((d) => d.name === 'tty_close')
1912
+ const list77 = toolDefs.find((d) => d.name === 'tty_list')
1913
+ const capture77 = toolDefs.find((d) => d.name === 'tty_capture')
1914
+ const send77 = toolDefs.find((d) => d.name === 'tty_send')
1915
+ if (open77 === undefined || close77 === undefined || list77 === undefined || capture77 === undefined || send77 === undefined) {
1916
+ fail('B34 D77 工具集', '缺工具: ' + toolDefs.map((d) => d.name).join(','))
1917
+ } else {
1918
+ const opened = await open77.execute({ cwd: '/tmp', command: 'printf "D77_%s\\n" RETAINED' })
1919
+ const sid = opened.sid
1920
+ // 命令瞬间跑完:等它转成只读保留态(清单里带 exited:true)
1921
+ let entry = null
1922
+ for (let i = 0; i < 40; i++) {
1923
+ await sleep(150)
1924
+ entry = ((await list77.execute({})).sessions ?? []).find((x) => x.sid === sid)
1925
+ if (entry !== undefined && entry.exited === true) break
1926
+ }
1927
+ if (entry !== undefined && entry.exited === true && entry.retainMs === undefined) {
1928
+ pass('B34a 命令退出后会话仍在清单里(exited:true,默认不按时间释放)')
1929
+ } else {
1930
+ fail('B34a 命令退出后会话仍在清单里', JSON.stringify(entry))
1931
+ }
1932
+
1933
+ const read = await capture77.execute({ sid, lines: 100 })
1934
+ if (read.exited === true && String(read.tail).includes('D77_RETAINED')) {
1935
+ pass('B34b tty_capture 读得到退出前的输出(带 exited 标记)')
1936
+ } else {
1937
+ fail('B34b tty_capture 读得到退出前的输出', JSON.stringify(read).slice(0, 160))
1938
+ }
1939
+
1940
+ let refused = false
1941
+ try {
1942
+ await send77.execute({ sid, data: 'echo nope\n' })
1943
+ } catch {
1944
+ refused = true
1945
+ }
1946
+ if (refused) pass('B34c tty_send 对只读保留态明确拒写')
1947
+ else fail('B34c tty_send 对只读保留态明确拒写', '居然写进去了')
1948
+
1949
+ const closed = await close77.execute({ sid })
1950
+ const gone = !((await list77.execute({})).sessions ?? []).some((x) => x.sid === sid)
1951
+ if (closed.ok === true && gone) pass('B34d tty_close 释放保留态(关掉后从清单消失)')
1952
+ else fail('B34d tty_close 释放保留态', `ok=${String(closed.ok)} gone=${String(gone)}`)
1953
+ }
1954
+ }
1955
+
1956
+ // B35: `tty_open command=` 执行的是**整段 shell 代码**(D78)
1957
+ //
1958
+ // 旧实现把用户命令直接缀在 `exec` 后面——`exec` 只作用于简单命令,于是
1959
+ // `echo A; echo B` 只跑 A、`cd /tmp && pwd` 空输出、`echo X; exit 3` 报 0、
1960
+ // `for …` 直接 parse error(2026-09-27 报告)。这里用真 PTY 钉住五条形态,
1961
+ // 判据取「后半段的输出真的出现了」+「退出码取自最后一条」。
1962
+ console.log('\n[32] `command` 按 shell 语法整体执行(D78)')
1963
+ {
1964
+ const open = toolDefs.find((d) => d.name === 'tty_open')
1965
+ const close = toolDefs.find((d) => d.name === 'tty_close')
1966
+ const list = toolDefs.find((d) => d.name === 'tty_list')
1967
+ const capture = toolDefs.find((d) => d.name === 'tty_capture')
1968
+ if (open === undefined || close === undefined || list === undefined || capture === undefined) {
1969
+ fail('B35 D78 工具集', '缺工具: ' + toolDefs.map((d) => d.name).join(','))
1970
+ } else {
1971
+ /** 开一条命令会话并等它转成只读保留态(命令跑完),返回 { sid, entry }。 */
1972
+ const openAndSettle = async (command) => {
1973
+ const opened = await open.execute({ cwd: '/tmp', command })
1974
+ for (let i = 0; i < 80; i++) {
1975
+ await sleep(150)
1976
+ const entry = ((await list.execute({})).sessions ?? []).find((x) => x.sid === opened.sid) ?? null
1977
+ if (entry !== null && entry.exited === true) return { sid: opened.sid, entry }
1978
+ }
1979
+ return { sid: opened.sid, entry: null }
1980
+ }
1981
+ const readTail = async (sid) => String((await capture.execute({ sid, lines: 80 })).tail ?? '')
1982
+ const opened = []
1983
+ try {
1984
+ // ① `a; b`:旧实现只跑第一条
1985
+ const semi = await openAndSettle('echo A; echo B; echo C; echo D')
1986
+ opened.push(semi.sid)
1987
+ const semiTail = await readTail(semi.sid)
1988
+ if (['A', 'B', 'C', 'D'].every((m) => semiTail.includes(m))) pass('B35a 分号列表整段执行(A/B/C/D 都在)')
1989
+ else fail('B35a 分号列表整段执行', JSON.stringify(semiTail).slice(0, 160))
1990
+
1991
+ // ② `cd x && cmd`:agent 最惯用的写法,旧实现空输出
1992
+ const and = await openAndSettle('cd /tmp && pwd')
1993
+ opened.push(and.sid)
1994
+ const andTail = await readTail(and.sid)
1995
+ if (andTail.includes('/tmp')) pass('B35b `cd && cmd` 完整执行(拿到 /tmp)')
1996
+ else fail('B35b `cd && cmd` 完整执行', JSON.stringify(andTail).slice(0, 160))
1997
+
1998
+ // ③ 退出码取自命令列表最后一条(旧实现取被 exec 的第一条)
1999
+ const rc = await openAndSettle('echo X; exit 3')
2000
+ opened.push(rc.sid)
2001
+ if (rc.entry !== null && rc.entry.exitCode === 3) pass('B35c 退出码取自最后一条(echo X; exit 3 → exitCode=3)')
2002
+ else fail('B35c 退出码取自最后一条', JSON.stringify(rc.entry))
2003
+
2004
+ // ④ 复合语句(for)不再 parse error
2005
+ const loop = await openAndSettle('for i in 1 2 3; do echo L$i; done')
2006
+ opened.push(loop.sid)
2007
+ const loopTail = await readTail(loop.sid)
2008
+ if (['L1', 'L2', 'L3'].every((m) => loopTail.includes(m))) pass('B35d `for …; do …; done` 整段执行(L1/L2/L3 都在)')
2009
+ else fail('B35d `for …` 整段执行', JSON.stringify(loopTail).slice(0, 200))
2010
+
2011
+ // ⑤ 命令里的单引号安全穿过包装层
2012
+ const quoted = await openAndSettle("echo 'QUOTED-OK'")
2013
+ opened.push(quoted.sid)
2014
+ const quotedTail = await readTail(quoted.sid)
2015
+ if (quotedTail.includes('QUOTED-OK')) pass("B35e 命令内的单引号不被包装层吃掉(echo 'QUOTED-OK')")
2016
+ else fail('B35e 命令内的单引号', JSON.stringify(quotedTail).slice(0, 160))
2017
+ } catch (error) {
2018
+ fail('B35 D78 `command` 按 shell 语法整体执行', error.message)
2019
+ }
2020
+ for (const sid of opened) {
2021
+ try {
2022
+ await close.execute({ sid })
2023
+ } catch {
2024
+ /* 已释放 */
2025
+ }
2026
+ }
2027
+ }
2028
+ }
2029
+
1899
2030
  // B33: 输出契约(所有已调用工具的真实返回值都符合各自声明的 output.schema)
1900
2031
  //
1901
2032
  // 这一条是 §B12e 的补充:B12e 只证明 schema 形状受支持,证明不了返回值合法。
1902
2033
  // 真实宿主对输出做 additionalProperties:false 校验,违约会直接把工具调用变成
1903
2034
  // Error(tty_list 加 owner 漏改 schema 即此)。
1904
- console.log('\n[31] 输出契约')
2035
+ console.log('\n[33] 输出契约')
1905
2036
  {
1906
2037
  if (outputViolations.length === 0) pass('B33 工具返回值符合声明的 output.schema')
1907
2038
  else fail('B33 工具返回值符合声明的 output.schema', outputViolations.slice(0, 3).join(' | '))
@@ -87,6 +87,12 @@ function openSession(port) {
87
87
  /** ConPTY 里按 Enter 是 \r(顺带补 \n 兼容两种翻译),cmd 才会执行。 */
88
88
  const ENTER = '\r\n'
89
89
 
90
+ /**
91
+ * 注册进来的 agent 工具定义(W6 要**直接调 `tty_send` 的工具路径**——D74 修的就是它)。
92
+ * 原先 stub 的 `register` 只吞掉返回值,等于这里没有 agent 工具入口。
93
+ */
94
+ const TOOLS = new Map()
95
+
90
96
  async function run() {
91
97
  const app = new Context()
92
98
  const wsFiber = app.plugin(WebServerRuntime, { host: '127.0.0.1', port: 0 })
@@ -97,7 +103,7 @@ async function run() {
97
103
  // DSH ≥0.1.7 的 settings 服务(SettingsForms):describe / update / configure。
98
104
  // 本用例不测配置持久化,空 describe 即可(插件的 settings effect 拿到空值)。
99
105
  ctx.provide('settings', { describe: () => [], update: async () => {}, configure: () => () => {} })
100
- ctx.provide('tools', { register: () => () => {} })
106
+ ctx.provide('tools', { register: (definition) => { TOOLS.set(definition.name, definition); return () => {} } })
101
107
  },
102
108
  })
103
109
  await stubFiber.await()
@@ -171,6 +177,99 @@ async function run() {
171
177
  fail('W5 kill 后可重新 spawn', error.message)
172
178
  }
173
179
  try { s2.client.close() } catch { /* 已关闭 */ }
180
+
181
+ // W6:agent 侧 `tty_send` 发**裸 LF** 也能提交命令(D74,2026-09-27 真机报告)
182
+ //
183
+ // 为什么必须在真机上钉这条:报告的第 1 条是 conhost 的**真实行为**(Enter 是 CR,
184
+ // 裸 LF 只把光标下移、不提交命令行)。本地单测只能在 macOS/Linux 上 mock
185
+ // `process.platform` 验「插件有没有归一化」,验不了「归一化之后 conhost 真的执行了」。
186
+ // 这里用 `%OS%` 展开做判据,理由同 W3:回显里只有 `%OS%` 字面量。
187
+ console.log('\n[W6] tty_send 的 \\n 归一化(真实 conhost:裸 LF 不提交命令)')
188
+ let agentSid = null
189
+ try {
190
+ const open = TOOLS.get('tty_open')
191
+ const send = TOOLS.get('tty_send')
192
+ const capture = TOOLS.get('tty_capture')
193
+ if (open === undefined || send === undefined || capture === undefined) {
194
+ throw new Error('agent 工具没注册进 stub(注册到的:' + [...TOOLS.keys()].join(', ') + ')')
195
+ }
196
+ const opened = await open.execute({ cwd: process.cwd(), cols: 100, rows: 30 })
197
+ agentSid = opened.sid
198
+ await send.execute({ sid: agentSid, data: 'echo IT_LF_%OS%\n' })
199
+ const deadline = Date.now() + 15000
200
+ let tail = ''
201
+ for (;;) {
202
+ tail = String((await capture.execute({ sid: agentSid, lines: 60 })).tail ?? '')
203
+ if (/IT_LF_Windows_NT/.test(tail)) break
204
+ if (Date.now() > deadline) throw new Error('15s 内没等到 %OS% 展开;尾部:' + tail.slice(-300))
205
+ await sleep(200)
206
+ }
207
+ pass('W6 tty_send 的裸 LF 在 ConPTY 上提交并执行了命令(D74:win32 归一化成 CRLF)')
208
+ } catch (error) {
209
+ fail('W6 tty_send 的裸 LF 提交命令(D74)', error.message)
210
+ }
211
+ if (agentSid !== null) {
212
+ try {
213
+ await TOOLS.get('tty_close').execute({ sid: agentSid })
214
+ } catch {
215
+ /* 已关闭 */
216
+ }
217
+ }
218
+
219
+ // W7:进程退出后转「只读保留」——输出还能读回来(D77,issue #4 的正题)
220
+ //
221
+ // 为什么必须在真机上钉:条目链路在真实 ConPTY 上才完整——`command` 型会话跑完,
222
+ // ConPTY 侧进程退出、句柄收尾、宿主把会话**留在表里**而不是摘掉;本地单测用的是
223
+ // 假 PTY,验不到「真机上退出之后 tty_capture 还读得到输出」。
224
+ console.log('\n[W7] 退出后的只读保留(D77)')
225
+ let retainedSid = null
226
+ try {
227
+ const open = TOOLS.get('tty_open')
228
+ const list = TOOLS.get('tty_list')
229
+ const capture = TOOLS.get('tty_capture')
230
+ const send = TOOLS.get('tty_send')
231
+ if (open === undefined || list === undefined || capture === undefined || send === undefined) {
232
+ throw new Error('agent 工具没注册进 stub(注册到的:' + [...TOOLS.keys()].join(', ') + ')')
233
+ }
234
+ // `command` 直接跑一条会结束的命令(正是上报现场那种用法)
235
+ const opened = await open.execute({ cwd: process.cwd(), command: 'echo IT_RETAIN_%OS%' })
236
+ retainedSid = opened.sid
237
+ const deadline = Date.now() + 20000
238
+ let entry = null
239
+ for (;;) {
240
+ entry = (await list.execute({})).sessions.find((x) => x.sid === retainedSid) ?? null
241
+ if (entry !== null && entry.exited === true) break
242
+ if (Date.now() > deadline) throw new Error('20s 内没等到 exited:true;最近一条:' + JSON.stringify(entry))
243
+ await sleep(200)
244
+ }
245
+ pass('W7a 命令退出后会话仍是只读保留态(exited:true)')
246
+ const read = await capture.execute({ sid: retainedSid, lines: 60 })
247
+ if (read.exited === true && /IT_RETAIN_Windows_NT/.test(String(read.tail ?? ''))) {
248
+ pass('W7b 退出之后 tty_capture 仍读得到退出前的输出')
249
+ } else {
250
+ fail('W7b 退出之后 tty_capture 仍读得到输出(D77)', JSON.stringify(read).slice(0, 200))
251
+ }
252
+ let refused = false
253
+ try {
254
+ await send.execute({ sid: retainedSid, data: 'echo nope\n' })
255
+ } catch {
256
+ refused = true
257
+ }
258
+ if (refused) pass('W7c 对只读保留态 tty_send 明确拒写')
259
+ else fail('W7c 对只读保留态 tty_send 明确拒写', '居然写进去了')
260
+ } catch (error) {
261
+ fail('W7 退出后的只读保留(D77)', error.message)
262
+ }
263
+ if (retainedSid !== null) {
264
+ try {
265
+ await TOOLS.get('tty_close').execute({ sid: retainedSid })
266
+ const gone = !(await TOOLS.get('tty_list').execute({})).sessions.some((x) => x.sid === retainedSid)
267
+ if (gone) pass('W7d tty_close 释放保留态(关掉后从清单消失)')
268
+ else fail('W7d tty_close 释放保留态', '仍在清单里')
269
+ } catch (error) {
270
+ fail('W7d tty_close 释放保留态', error.message)
271
+ }
272
+ }
174
273
  }
175
274
 
176
275
  await run()