DSH / Atlas
2026-08-12implementedbug-fix

fix the pwsh terminal overlay duplicate-loader collision

修复 pwsh 终端 overlay 的重复 loader 冲突

`apps/web/tests/pwsh-terminal.e2e.ts` fails on every platform with `TypeError: duplicate loader entry id: tool-pwsh`, thrown from `vendor/loader/src/config/group.ts:64` while applying the web composition. The failing seed lane boots the full shipped bundle plus a test overlay, so the E2E never reaches its rendering assertion and every `check:ci:snapshot`/`test:web` run reports a red web test even though the feature u

Source compatibility: Chinese title uses a compatible non-canonical header

English

Problem

apps/web/tests/pwsh-terminal.e2e.ts fails on every platform with TypeError: duplicate loader entry id: tool-pwsh, thrown from vendor/loader/src/config/group.ts:64 while applying the web composition. The failing seed lane boots the full shipped bundle plus a test overlay, so the E2E never reaches its rendering assertion and every check:ci:snapshot/test:web run reports a red web test even though the feature under test is unrelated to the change under review.

The web E2E scaffold applies an extraOverlayPath after the shipped Web surface and base patches. pwsh-terminal.overlay.yml used an insert block to add a tool-pwsh row:

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

insert is correct only while tool-pwsh is absent from the composition. The id exists because 86b6979bdc (refactor(bundle): fold the Windows shell platform layer into the base rows) moved both shell stacks into the base bundle with inverted platform gates — packages/bundle/base/cordis.patch.yml declares tool-pwsh with disabled: !!js process.platform !== 'win32', so the row is present in the composition on every platform. Later, 42fc7c5ffb (refactor(preset): gate tool-pwsh by platform alongside tool-bash) added a web-app patch row that disables tool-pwsh for surfaces that use presets; a patch row cannot introduce an id, so it is not the source of the collision. The overlay's insert delivers a second row with the same id in the same loader group, and the loader rejects the pair at boot.

Decision

Replace the overlay's insert of tool-pwsh with a top-level id-targeted override:

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

The effective tool-pwsh state is a three-layer stack: the base row gates disabled on process.platform !== 'win32', the web-app overlay sets disabled: true unconditionally for preset surfaces, and this lane's override clears it back to disabled: false regardless of platform. An id-targeted top-level override replaces the composed row; only an insert would collide.

The lane also now disables pwsh-sandbox by id, symmetric with the existing bash-sandbox disable: the base gates pwsh-sandbox with disabled: !!js process.platform !== 'win32', so on Windows it would otherwise mount beside the inserted pwsh-local and both would register the same executor service. Disabling it keeps pwsh-local the lone executor on every platform.

The overlay header comment was updated to describe the full selection and the tool-pwsh inline comment now names the base row as the source of the id.

Alternatives considered

Keep the insert and change the web composition instead. Rejected, because the shipped web composition should keep the host tool-pwsh row disabled for every surface that uses presets; the overlay is the lane that deliberately needs it, so the by-id enable belongs there. The base row itself cannot be removed either: it is the platform-gated shell-stack declaration shared by every bundle.

Enable tool-pwsh in the insert block. Not possible: an insert of an id that already exists is the very duplicate being fixed. The row must be targeted by id, which is the top-level override form, not insert.

Patch tool-pwsh by id without setting disabled: false. Insufficient: the web-app overlay sets disabled: true unconditionally, and the base row's platform gate only applies where the web-app override is absent, so an override that only restates name leaves the row disabled and the lane renders no terminal card. The disabled: false is required.

Only disable bash-sandbox and rely on the platform gate to keep pwsh-sandbox off. Rejected: that holds on POSIX but breaks on Windows, where the base row leaves pwsh-sandbox enabled and it would collide with the inserted pwsh-local on the shared executor service. The lane's pwsh-sandbox disable keeps one executor on every platform.

Verification

Reverting the fix (restoring the insert of tool-pwsh) reproduces the exact duplicate loader entry id: tool-pwsh boot failure, confirming the override is load-bearing. With the fix in place pwsh-terminal.e2e.ts passes 2/2 on the same head — this exercises the POSIX seam, where the seeded pwsh call renders through the enabled tool-pwsh and the inserted pwsh-local. The seed lane requires a usable pwsh, so it skips on hosts without one; a pwsh binary is present on this machine and the test ran. The Windows path (base pwsh-sandbox mounted beside the inserted pwsh-local) is not exercised by any CI lane, whose test:web runs only on Linux; the overlay disables pwsh-sandbox to keep that path composable if it ever runs on a Windows dev machine.

Consequences

The web E2E seed lane that exercises PowerShell boot now composes instead of colliding, so check:ci:snapshot and test:web stop failing on the duplicate independently of the change under test. The pattern is general: a --patch/extraOverlayPath overlay must probe whether a row already exists in the bundle it augments before choosing insert over an id-targeted override; insert of an id that the base or shipped Web surface already declares is a boot-time duplicate.

中文

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:snapshottest:web 每次运行都报一个红的 web 测试,即便被测功能与评审中的改动无关。

web E2E scaffold 在已发布的 Web 表面与 base patches 之后应用 extraOverlayPathpwsh-terminal.overlay.ymlinsert 块新增 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-pwshdisabled: !!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-pwshinsert 替换成顶层按 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-pwshinsert)即复现同样的 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:snapshottest:web 不再与被测改动无关地在该 duplicate 上失败。该模式具有通用性:--patch/extraOverlayPath overlay 在决定用 insert 还是按 id override 之前,必须探测目标 bundle 是否已存在该行;对已由 base 或已发布 Web 表面声明的 id 做 insert,是启动期重复。