deepseek-harness/.agents/notes/implemented/bug-fix/2026-08-12-fix-pwsh-terminal-overlay-dup.zh.md
Chinesezjc 9523dff0fd fix(web): resolve the pwsh-terminal overlay duplicate-loader entry
The web E2E seed lane for the pwsh terminal card failed on every platform
with `duplicate loader entry id: tool-pwsh`. The overlay inserted a new
tool-pwsh row, but the base bundle has declared that id since the shell
platform layer moved into it, so the overlay's insert delivered a second
row with the same id and the loader rejected the pair at boot.

Enable the existing tool-pwsh row by id instead of inserting it, and
disable pwsh-sandbox so the inserted pwsh-local is the lone executor on
every platform (the base gates pwsh-sandbox on win32, which would
otherwise collide with the inserted executor there).
2026-08-12 23:27:45 +08:00

4.9 KiB
Raw Blame History

Agent Note:修复 pwsh 终端 overlay 的重复 loader 冲突

Status: implemented

English | 中文

Problem

apps/web/tests/pwsh-terminal.e2e.ts 在所有平台上都以 TypeError: duplicate loader entry id: tool-pwsh 失败,由 vendor/loader/src/config/group.ts:64 在应用 web 组合时抛出。该失败的 seed 通道会启动完整发布的 bundle 加一个测试 overlay,因此 E2E 永远到不了渲染断言,导致 check:ci:snapshot 与 test:web 每次运行都报一个红的 web 测试,即便被测功能与评审中的改动无关。

web E2E scaffold 在已发布的 Web 表面与 base patches 之后应用 extraOverlayPath。pwsh-terminal.overlay.yml 用 insert 块新增 tool-pwsh 行:

- insert:
    - id: pwsh-local
      name: '@deepseek-ai/dsh-pwsh-local'
    - id: tool-pwsh
      name: '@deepseek-ai/dsh-tool-pwsh'

insert 仅在组合中不存在 tool-pwsh 时才正确。该 id 存在是因为 86b6979bdc(refactor(bundle): fold the Windows shell platform layer into the base rows)把两套 shell 栈以互逆的平台门移进了 base bundle —— packages/bundle/base/cordis.patch.yml 声明 tool-pwsh 且 disabled: !!js process.platform !== 'win32',于是该行在每个平台都存在于组合中。随后 42fc7c5ffb(refactor(preset): gate tool-pwsh by platform alongside tool-bash)往 web-app patch 里加了一行对使用 preset 的表面禁用 tool-pwsh 的行;patch 不能引入 id,因此它不是冲突来源。overlay 的 insert 于是在同一个 loader 组里再送一个同 id 的行,loader 在启动时拒绝这对重复。

Decision

把 overlay 对 tool-pwsh 的 insert 替换成顶层按 id override:

- id: tool-pwsh
  name: '@deepseek-ai/dsh-tool-pwsh'
  disabled: false

有效的 tool-pwsh 状态是三层栈:base 行把 disabled 门在 process.platform !== 'win32' 上,web-app overlay 对 preset 表面无条件设 disabled: true,本通道的 override 无论平台都把 disabled: false 还回去。id 定位的顶层 override 替换组合后的行;只有 insert 才会相撞。

该通道现在也按 id 禁用 pwsh-sandbox,与既有的 bash-sandbox 禁用对称:base 以 disabled: !!js process.platform !== 'win32' 门住 pwsh-sandbox,因此在 Windows 上它本会与插入的 pwsh-local 并存,两者会注册同一个 executor 服务。禁用它让 pwsh-local 在每个平台上都是唯一 executor。

overlay 头部注释已更新为完整描述选择,tool-pwsh 行内注释现在把 base 行标为该 id 的来源。

Alternatives considered

保留 insert、改 web 组合。 拒绝。已发布的 web 组合应在所有使用 preset 的表面上保持 host tool-pwsh 行禁用;overlay 才是那条刻意需要该行的通道,因此按 id 启用应放在那里。base 行本身也不能移除:它是所有 bundle 共享的平台门 shell 栈声明。

在 insert 块里启用 tool-pwsh。 不可行。对已存在的 id 做 insert 正是这里要修的重复。该行必须按 id 定位,即顶层 override 形式,而非 insert。

只按 id 改 tool-pwsh 而不设 disabled: false。 不充分。web-app 无条件设 disabled: true,base 行的平台门只在 web-app override 缺失处生效,因此只重申 name 的 override 会让行保持禁用,通道渲染不出终端卡。disabled: false 是必需的。

只禁用 bash-sandbox、依赖平台门让 pwsh-sandbox 保持关闭。 拒绝。在 POSIX 上成立,但在 Windows 上会失败:base 行让 pwsh-sandbox 启用,它会与插入的 pwsh-local 在共享 executor 服务上相撞。本通道禁用 pwsh-sandbox 让每个平台只有唯一 executor。

Verification

把修复还原(恢复对 tool-pwsh 的 insert)即复现同样的 duplicate loader entry id: tool-pwsh 启动失败,证实 override 是有效的。修复后同一 head 上 pwsh-terminal.e2e.ts 2/2 通过 —— 这作用于 POSIX seam,播种的 pwsh 调用经启用的 tool-pwsh 与插入的 pwsh-local 渲染出来。该 seed 通道需要可用的 pwsh,无此二进制的主机会跳过;本机有 pwsh,测试实际跑过。Windows 路径(base pwsh-sandbox 与插入的 pwsh-local 并存)没有任何 CI lane 覆盖,其 test:web 只在 Linux 上跑;overlay 禁用 pwsh-sandbox 让该路径在真到 Windows 开发机运行时可组合。

Consequences

用于执行 PowerShell 启动的 web E2E seed 通道现在能组合而非相撞,因此 check:ci:snapshot 与 test:web 不再与被测改动无关地在该 duplicate 上失败。该模式具有通用性:--patch/extraOverlayPath overlay 在决定用 insert 还是按 id override 之前,必须探测目标 bundle 是否已存在该行;对已由 base 或已发布 Web 表面声明的 id 做 insert,是启动期重复。