16 KiB
16 KiB
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 仍裸 importanser/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 条结果。同一 commit8ae527170的另一次 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 上仍复现(run34574847774:126/127 文件全过、0 FAIL、Unhandled Error: Worker exited unexpectedly,丢结果的那个 worker 正是跑tests/native-surface.spec.ts的)。该次日志里native-surface.spec.ts零结果,与历史两次崩溃同形(34500290681125/126、34448911025123/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;run34490912649先刷 3062 条 ERESOLVE、9 分钟后FATAL ERROR: Ineffective mark-compacts near heap limitexit 134。同一机制在 2026-09-09 的 alpha 线也复现过一次(run34363627184,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:mount7 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连续两次全绿(同一 commit5451f5c)——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:mount7 passed、聚合双挂载通过。 - 首次真实结果的证伪(已修正):本 PR 的第一版修复在同一 commit 上仍红两处,
.github/workflows/ci.yml的改动因此被真实证据改过一轮——见 C 节的「一次被真实结果否掉的中间方案」与 A 节第三个文件(tests/git.spec.ts:85,9607ms)。 - B 类的实测结论(已按"升级而非掩盖"走完两轮):
--maxWorkers=2下仍崩溃(run34574847774),故升级为--maxWorkers=1(单 fork、零回收)。这不等于证明了根因(4 次崩溃的一致形态是「N-1 文件有结果 + teardown 期静默退出」,只能说明是 worker 回收竞态而非测试失败);收敛判据是单 worker 下连续两次ci-windows全绿——已达成:run 34575721734(PR 触发)与 run 34576146970(同 commit4fe67e3的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:mount7 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 后由 LaunchAgentcom.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 发布由用户决定)。