A completed pwsh foreground call now presents as the bash tool's terminal card with the parsed exit-status pill instead of a generic console fence, and the collapsed row classifies as the shell family (Pwsh title). The marker-to-exit-status parse moves from dsh-tool-bash's private render module into the @deepseek-ai/dsh-bash seam so both shell tools share one inverse of the marker contract (the bash-env precedent). The Web UI needs no per-tool code: the terminal-card bridge maps any card:'terminal' view. Coverage: dsh-bash owns the parse edge cases; the tool-pwsh presenter suite mirrors tool-bash's; the client row-model suite pins the Pwsh shell row; the new keyless pwsh-terminal web lane seeds an authored session, presents it through the real tool on replay, and pins the card golden. TUI is out of scope: the TUI package was removed (ed30088adb), so the Web surface is the only UI the gap affected; the roadmap proposal's stage 2 is updated accordingly.
4.9 KiB
Agent Note: pwsh 工具与 bash 对齐
Status: implemented
English | 中文
问题
首个 Windows 原生基础交付的 dsh-tool-pwsh 是刻意最小的画像——仅前台、无后台任务、受管环境只有三个硬编码 DSH_* 键、以及一个未声明就偏离 bash 工具的 marker 故事("恒打 [exit code: N]")。对该变更的 review 发现模型可见契约与实现脱节:描述承诺了渲染器从未执行的 spill 路径报告,README 宣称了不存在的导出与工具未做的渲染,工具自己的测试还钉死了有损行为。最小画像还让 DSH_* contributor seam 因缺席而重复:向 ctx.bashEnv 贡献环境事实的插件对 pwsh 调用毫无作用。
决策
dsh-tool-pwsh 现在逐调用镜像 dsh-tool-bash,减去 sandbox 面,其模型可见文本精确描述这一行为:
- 渲染完全采用 bash 故事:stdout、带标记的
[stderr]段、带 spill 路径的截断通知、空体渲染(no output)、退出 marker 仅限非零退出——干净退出不产生 marker。描述与tool:pwshprompt section 精确陈述这一点("Non-zero exits are reported as[exit code: N]markers"),刻意不复制 bash prompt 中与其自身渲染矛盾的 "every result" 措辞。 run_in_background经通用任务运行时接线,与 bash 工具完全一致:预检、owner 注册、task_output/task_kill控制与相同的结果映射。其背后是pwsh-local早已镜像好的start()句柄。DSH_*环境共享而非复制:BashEnvRegistry从dsh-tool-bash迁入新的工具无关包@deepseek-ai/dsh-bash-env(ctx.bashEnv+ 内置事实 + session-persistence contributor),两个 shell 工具都注入它。contributor 对 pwsh 调用与 bash 调用一视同仁,并消化了 bash 工具的FIXME(bash-env-ownership)。- Windows 现实在 bash 无对应处钉死:每条命令都在 UTF-8 输出 preamble 下运行,使 Windows PowerShell 5.1 兜底无法经 UTF-8 解码的 collector 破坏非 ASCII 输出;prompt 教授 Windows 强制终止以无 signal 的 exit 1 结算。
- 范围外,不变:sandbox 升级(等待 Windows-confining 执行器)与持久 PTY shell(后端仅限 Linux/macOS;ConPTY 属路线图)。带退出 pill 的 pwsh 专属 terminal 卡已随 pwsh UI 呈现与 bash 对齐 决策另行交付。
备选方案
保留最小画像,只修声明。 否决:review 的核心发现是"从 bash 复制的文本契约在缺少对应实现时会漂移";最小工具加准确声明仍让 pwsh 调用没有后台执行、没有 contributor 对等、并留下一个必须永远重新辩护的偏离 marker 故事。
在加载时拒绝不匹配的执行器方言。 合并前尝试过并撤回:在 BashExecutor 上加 ShellDialect 标记(bash | powershell),两个 shell 工具在挂载的执行器说另一种方言时抛错。它迫使每个执行器实现——包括每个测试与示例的 fake——都要声明 dialect,为一道仓内及合理部署中都没有目标可拦的护栏(交付组合总是把 tool-pwsh 配 dsh-pwsh-local、tool-bash 配 dsh-bash-local)给每个 shell 工具测试添噪。配对契约改由各工具 README 记录。
提取完全共享的工具实现基座(抽象 shell 方言,两个薄叶子)。 考虑后推迟:bash-env 提取与结构镜像(render.ts/background.ts 孪生)是它要立足的基础;在出现第三种方言或持久 PTY 孪生、让抽象的形态可观察之前,不做完整基座。
后果
- bash 与 pwsh 工具在前台与后台 shell 工作(减 sandbox)上行为可互换,pwsh 的 prompt/描述句每句都有渲染器背书——reviewer 的“拿代码 grep 对证”检查通过。
- 对齐也反向发生过一次:pwsh 工具的结构化前台中止(
HarnessError('tool call aborted', TOOL_ABORTED),name 为AbortError)被回移到 bash 工具,取代其无码的Error('command aborted')——这是模型可见/入日志的变更,由两侧的精确形状测试与 cancel-tool-calls fixture 钉住。 @deepseek-ai/dsh-bash-env成为新的交付包;dsh-tool-bash的dshHome配置迁往那里,因此挂载 shell 工具的组合也必须挂载bash-env(spine bundle 已如此)。- Windows 专属语义(CRLF 归一化、强制终止 exit-1/signal-null、仅 POSIX 的自信号)一如既往由测试钉住。
- pwsh 工具的 per-file 覆盖门禁由可脚本化的 fake-executor 套件(
tests/tools.spec.ts)承担;真实 pwsh 的集成与 Loader 组合套件在无pwsh的宿主自跳过,与 bash 套件的分工一致。 - 路线图提案的 parity 阶段已交付;terminal 卡呈现阶段随 pwsh UI 呈现与 bash 对齐 决策交付(TUI 本身已移除),剩余阶段是 Windows 默认组合。