Files
apes-sidebar/docs/plans/2026-09-10-dsh-0.1.5-rc.2-adaptation.md
T

16 KiB
Raw Blame History

DSH 0.1.5-rc.2 适配(v0.19.1 基线)+ CI 三类失败修复

日期:2026-09-10(复核 2026-09-11) 分支:feat/dsh-0.1.5-rc.2

背景

DSH dsh-v0.1.5-rc.1..dsh-v0.1.5-rc.2(上游 4 个 commit / 300 个变更文件,npm 发布 2026-09-10T14:57Z,dist-tag next;latest 仍是 rc.1)是 0.1.5 线的第二个候选版。本计划记录该 delta、插件对它的结论(无需任何运行时/类型层适配,只推进钉版),以及同一时间窗内 ci-windows / plugin-mount 两个车道真实存在的三类 CI 失败与修法。上一版(rc.1)记录见 2026-09-10-dsh-0.1.5-rc.1-adaptation.md;仓库级适配要点同步到 AGENTS.md §2/§3。

上游 delta(rc.1 → rc.2,影响本插件的部分:无)

300 个文件里绝大多数是各包 package.json 的 version 单行改动(1+1-)。逐文件过完后的真实代码改动只有四处:

# 上游变更 文件 对插件的影响
1 消息反馈改为对称提交(弹窗、动作按钮、控制器、槽位、i18n) packages/client/ui-message-feedback/src/client/* 无——插件不注册反馈槽、不读该控制器
2 产物卡片内边距与呈现微调 packages/client/ui-deliverables/src/client/*、ui-chat/src/client/chat/TurnTailNodeView.module.css 无——插件不消费这两个包的组件,也不做会话尾迹布局
3 CodeFileIcon 的 477 行内联 SVG 拆进新增的 code-file-icon-artwork.ts(另有 .manifest.json 记录设计导出摘要) packages/client/ui-primitives/src/CodeFileIcon.tsx 无——CodeFileIcon 的导出面与 props 未变,且插件本来就不用它(插件文件树用 IconCodeOutline16;#611 的文件图标主题还在 PR #594,未进 main)
4 其余全部为版本号 各 package.json 无

明确未变(不必再核):

  • packages/api/*(session-controller / workspace-controller / gateway / remotes)、packages/host/*、packages/session/*、packages/agent/*——零变更;除 packages/feedback/message-feedback/src/types.ts(1 行)外零类型文件变更。
  • 斜杠 RPC 方言、一次性 token 鉴权、会话事件模型、sidebarRight / sidebarRightTabs 承载面、SidebarRightGuideEntry.description 的 ≤4 渲染规则:全部沿用 rc.1 结论。
  • @deepseek-ai/dsh-client-ui-primitives 仍不声明 dependencies(bundle 仍裸 import anser / shiki / @shikijs/langs/* / mdast-util-* / micromark-* / katex)——提升进 devDependencies 的那组包继续不得回退。

决策

  • peer 下限保持 ^0.1.5-rc.1 不动:rc.2 无契约变化,^0.1.5-rc.1 天然容纳它,rc.1 用户无需升级即可用新版插件。因此本版是纯 patch 的 0.19.1,只推进 devDependency 钉版、CI 挂载钉版与 SIDEBAR_SERVICE_VERSION。
  • engines.dsh 保持 >=0.1.5-rc.1:与 peer 下限同源(同一个支持范围,两处不能分叉)。
  • CI 挂载车道钉 rc.2:真机证据要落在最新版上;latest 仍是 rc.1 只是上游的发布节奏,与本插件支持范围无关。
  • 不为此版写运行时兼容层:上游 delta 里没有本插件触达的面,写兼容层就是无据的复杂度。

CI 三类失败(2026-09-09/10 窗口,60 次已完成 run 的取证)

窗口内 ci-windows|Test 失败 8 次、plugin-mount|Install dsh CLI (pinned) 失败 4 次。逐条读日志后归为三类,其中两类是真实缺陷、一类是运维噪音:

A. Windows 真实超时(6/8 次 ci-windows 失败,主因)

  • 证据:run 34494370187、34490215638、34459499945(3 次 attempt 全红)、34372999975、34322271074、34319666611 均为 Error: Test timed out in 5000ms,位置 tests/agent-pty.spec.ts:71:3 / :106:3;tests/install-powershell.spec.ts:105:41 的 powershell.exe 单测自身耗时 12151ms 后才超时。
  • 根因:vitest.config.ts 没有任何 testTimeout 配置(默认 5000ms),而这些 spec 每个用例都要真起一个 PowerShell + ConPTY 对;tests/agent-pty.spec.ts 的 waitForTranscript 默认预算也是 5000ms——内层轮询吃掉整个对外预算,结构上必然超时。
  • 修法:全局 testTimeout: 15_000(vitest.config.ts)+ 两个最重的 describe 显式 { timeout: 30_000 }(vitest 4 的 describe 级选项,已实测生效)+ waitForTranscript 默认预算降到 15s。为什么是全局而不是逐文件:本 PR 第一次跑真实 Windows 时,同一个 5000ms 默认又在第三个文件上翻车——tests/git.spec.ts:85「caps status entries at the truncation limit」耗时 9607ms(构造病态 untracked 集合 + 真实 git 调用)。三个不同文件、同一个根因,逐文件加超时是打地鼠;15s 是默认值的 3 倍、也是 Windows 上实测最大单测耗时的 ~1.5 倍,而 pty / powershell 两类最重的用例各有自己的 30s 预算。

B. Windows worker 静默死亡(2 次,非确定性)

  • 证据:run 34500290681(295615abb)、34448911025(bbf953b8a) 报 [vitest-pool]: Worker forks emitted error / Caused by: Error: Worker exited unexpectedly(Errors 1 error),同一份日志里 0 FAIL、125 个文件全过;后者静默吞掉一个文件的 10 条结果。同一 commit 8ae527170 的另一次 run 里 ci-windows 是绿的 → 该步骤可证伪地非确定。
  • 归因(推断,非确证):真起进程的 spec 有 5 个(agent-pty / pty-deps / pty-helpers / install-powershell / smoke),node-pty 的 ConPTY 辅助进程与冷启 powershell.exe 都绑定控制台,在默认无界 fork 池下并行抢占;本地 macOS 无法复现该模式,因此不做无证据的猜测性改动(不加 retry,不改默认 pool)。
  • 修法(两次迭代,第一次被真实结果证否):先上 test:windows(vitest run --maxWorkers=2)——真实 Windows 上仍复现(run 34574847774:126/127 文件全过、0 FAIL、Unhandled Error: Worker exited unexpectedly,丢结果的那个 worker 正是跑 tests/native-surface.spec.ts 的)。该次日志里 native-surface.spec.ts 零结果,与历史两次崩溃同形(34500290681 125/126、34448911025 123/124——都是「N-1 个文件有结果 + teardown 期 worker 静默退出」)。
  • 迭代后的修法:--maxWorkers=1(整个套件跑在一个 fork 里,零 worker 回收)。理由:跨 4 次崩溃的一致形态是「worker 回收/退出竞态」,而不是某个测试失败;单 worker 从根上取消这个竞态,代价只是墙钟时间(本地 14s → 41s,Windows 步骤仍在 30 分钟 job 预算内)。仍不加 retry:retry 会把真实回归一起吞掉。

C. plugin-mount 的 npm 安装失败(4 次:2× ETARGET + 2× OOM)

  • 证据:run 34492160123 / 34491256626 报 npm error notarget No matching version found for @deepseek-ai/dsh-tool-bash-persistent@^0.1.5-rc.2 / @deepseek-ai/dsh-sandbox-windows-acl@^0.1.5-rc.2;run 34490912649 先刷 3062 条 ERESOLVE、9 分钟后 FATAL ERROR: Ineffective mark-compacts near heap limit exit 134。同一机制在 2026-09-09 的 alpha 线也复现过一次(run 34363627184,1808 条 ERESOLVE → OOM);同期成功的安装是 added 521 packages in 19s、0 条 ERESOLVE。
  • 根因:钉版并没有真的钉住。@deepseek-ai/dsh@0.1.5-rc.1 的传递依赖声明为浮动 ^0.1.5-rc.1,会被上游分阶段发布中的 rc.2 满足(rc.2 的 14:43–14:57 逐个包上线),于是 npm 组出 rc.1/rc.2 混合 peer 图 → 解析器爆炸(OOM),或对尚未发布的兄弟包硬报 ETARGET(两个 ETARGET 分别在该包上线前 5.5 分钟与 25 秒)。
  • 修法(.github/workflows/ci.yml):钉一个已完整发布的 rc.2(修 ETARGET),并加 NODE_OPTIONS=--max-old-space-size=4096(修 OOM)。
  • 一次被真实结果否掉的中间方案(值得记):第一版修复还加了 --legacy-peer-deps(想法是「跳过 peer 协商即与发布窗口解耦」)。真实 Windows 结果表明它只是把安装弄坏而不是弄稳:它跳过的正是全局安装必须提供的 peer,而 @deepseek-ai/dsh-app-boot 在 boot 时 require 的 @deepseek-ai/cordis-plugin-group 是 peer 而不是 dependency,于是 CLI 在冒烟开始前就以 ERR_MODULE_NOT_FOUND 死掉(run 34560785101 的 plugin-mount)。本地复现并验证:同一命令去掉该 flag 后安装树完整(dsh/node_modules/@deepseek-ai/cordis-plugin-group 存在),且 DSH_CMD 指向这个 classic 安装的 test:mount 7 passed——宿主自带依赖,插件侧看不到差别。
  • 顺带修掉一处过时注释(原文断言「rc.1 同时是 latest 与 next」——现在 latest=rc.1、next=rc.2);这条注释正是浮动范围隐患长期不可见的来源。

改动清单(子系统级)

子系统 文件 变更
基线 package.json version → 0.19.1;dsh-* devDependencies 全部钉 0.1.5-rc.2(含 dsh-client-locale,上游仍与 DSH 同 tuple 发版);peerDependencies 一律保持 ^0.1.5-rc.1
基线 pnpm-lock.yaml 锁文件对齐 rc.2
基线 dsh.plugin.json version → 0.19.1;engines.dsh 保持 >=0.1.5-rc.1(与 peer 下限同源)
基线 src/client/service.ts SIDEBAR_SERVICE_VERSION → 0.19.1(tests/service.spec.ts 断言它 === package.json 的 version)
CI .github/workflows/ci.yml mount 车道钉 @deepseek-ai/dsh@0.1.5-rc.2 + NODE_OPTIONS=--max-old-space-size=4096(C 类;不用 --legacy-peer-deps,理由见 C 节);ci-windows 的 Test 改跑 pnpm test:windows(B 类);注释同步事实
CI package.json 新增 scripts.test:windows(vitest run --maxWorkers=2)
CI vitest.config.ts 全局 testTimeout: 15_000(A 类;覆盖 git / powershell / pty 三类真起进程的 spec,逐文件打地鼠的做法在真实 Windows 上被证否)
CI tests/agent-pty.spec.ts AgentPtyRegistry describe 显式 { timeout: 30_000 };waitForTranscript 默认预算 5000 → 15_000(A 类)
CI tests/install-powershell.spec.ts PowerShell installer entry points describe 显式 { timeout: 30_000 }(A 类)
文档 docs/plans/2026-09-10-dsh-0.1.5-rc.2-adaptation.md 本计划
图标 src/client/file-icons.tsx / src/client/builtins/tab-icons.* / src/client/native/tab-adapter.tsx 文件图标改用宿主官方 FileTypeIcon;内置 tab 与原生芯片图标彩色——独立记录见 2026-09-11-file-icons-and-tab-glyphs.md
文档 AGENTS.md §2 CI 基线戳与 mount 车道说明、§3 标题/基线段(rc.2 仍无契约变化,只推进钉版)
文档 README.md / README_EN.md 支持版本徽章与说明、新增 ### v0.19.1 段
文档 docs/external-plugin-guide.md 顶部基线行 → v0.19.1 / DSH 0.1.5-rc.1+(已在 rc.2 上验证)
文档 tests/native-surface.spec.ts、tests/builtins.spec.ts、tests/e2e/mount.e2e.ts、src/client/service.ts、src/client/native/index.ts 注释里的 DSH 0.1.5-rc.1 → 0.1.5-rc.1+(同一行为在 rc.2 未变)

验证

  • 未执行的门禁与真机步骤都留空,由主代理实施后回填(本文件不预填未经执行的结论)。

回填(主代理实测)

  • 门禁(rc.2 钉版,macOS arm64):pnpm install 成功且锁文件对齐 rc.2;pnpm peers check = No peer dependency issues found;pnpm typecheck / pnpm lint / pnpm check:consumer-types 全绿;pnpm test = 126 files / 1312 passed / 9 skipped(与 rc.1 基线同数,无新增 skip)。
  • 真机挂载冒烟(rc.2):DSH_CMD 指向 npx -y --package @deepseek-ai/dsh@0.1.5-rc.2 dsh;见"落地"节的实测计数。
  • 真实 Windows 收敛:ci-windows 连续两次全绿(同一 commit 5451f5c)——pull_request 自动触发的 run 34561189320 与随后 workflow_dispatch 的 run 34561457067,两次都是 126 files / 1318 passed / 3 skipped / 0 errors(Unhandled Errors 与 Worker exited unexpectedly 出现次数均为 0;同环境的 2026-09-09/10 窗口里这两行出现过 2 次)。同一分支的 plugin-mount 两次都绿:added 521 packages in 24s(0 条 ERESOLVE,与历史 OOM run 的 3062 条对比)、test:mount 7 passed、聚合双挂载通过。
  • 首次真实结果的证伪(已修正):本 PR 的第一版修复在同一 commit 上仍红两处,.github/workflows/ci.yml 的改动因此被真实证据改过一轮——见 C 节的「一次被真实结果否掉的中间方案」与 A 节第三个文件(tests/git.spec.ts:85,9607ms)。
  • B 类的实测结论(已按"升级而非掩盖"走完两轮):--maxWorkers=2 下仍崩溃(run 34574847774),故升级为 --maxWorkers=1(单 fork、零回收)。这不等于证明了根因(4 次崩溃的一致形态是「N-1 文件有结果 + teardown 期静默退出」,只能说明是 worker 回收竞态而非测试失败);收敛判据是单 worker 下连续两次 ci-windows 全绿——已达成:run 34575721734(PR 触发)与 run 34576146970(同 commit 4fe67e3 的 workflow_dispatch)都是 127 files / 0 errors,Unhandled Errors 与 Worker exited unexpectedly 出现 0 次。
  • 本地 3080 真机(DSH 0.1.5-rc.2 + 插件 0.19.1):部署与路由探针已完成(见"落地"节),GUI 人工验证由用户执行。

不做

  • 不为 rc.2 写任何运行时/类型层兼容层(上游 delta 未触及本插件的面)。
  • 不把 peer 下限抬到 ^0.1.5-rc.2(会无谓地把 rc.1 用户挡在上一版)。
  • 不为 B 类做无证据的猜测性改动:不加 vitest retry、不改默认 pool、不关掉真实 pty 测试。
  • 不改 DSH 源码(仓库硬约束 §1);不改 release.yml(0.19.1 无 prerelease 后缀 → 自动发 latest,符合 patch 语义)。

落地

  • PR:#626(feat/dsh-0.1.5-rc.2)。
  • 本地真机挂载冒烟(rc.2,macOS arm64):pnpm test:mount 7 passed(含 tab 体填充断言、指南 ≤4 条说明渲染断言、mermaid / README 预览与 sidechat 路由烟测);pnpm test:mount:aggregate 通过(聚合双挂载下插件自动退让,/sidebar/api 未知方法 404 与 terminal.deps 契约均符合)。
  • 本地 3080 实例部署(~/.dsh/profiles/web + ~/.dsh/dsh-web.sh):profile 依赖从 dsh-better-sidebar-0.19.0.tgz 改指 0.19.1 tarball 并 pnpm install(node_modules/dsh-better-sidebar/package.json = 0.19.1);dsh-web.sh 的 npx 钉版改 @deepseek-ai/dsh@0.1.5-rc.2,旧进程(PID 99521/99509/99507)定向 kill 后由 LaunchAgent com.pm2.dshweb.resurrect 自动拉起(新 PID 36025,npx 缓存 hash 因版本变更从 1da1392061ab1944 变为 c40503fdf38a82ea)。已核:新缓存里的 @deepseek-ai/dsh = 0.1.5-rc.2,/sidebar/api/shell.get → {"ok":true,"value":{"shell":"zsh","name":"zsh"}}、settings.get 回默认设置、terminal.deps → {"ok":true}(三条插件路由在生产实例上工作);GUI 人工验证由用户执行,结论回填到本节的下一步。
  • PR:#626(feat/dsh-0.1.5-rc.2)。PR 三个 check(ci / ci-windows / plugin-mount)在 run 34561189320 与 run 34561457067 上均绿。
  • 待回填:3080 人工验证结果(用户执行)、发版情况(v0.19.1 的 tag / npm 发布由用户决定)。