补丁锚点清单(patch anchors)

August 15, 2026 · View on GitHub

目标文件:$DSH_HOME/profiles/node_modules/@deepseek-ai/dsh-client-ui-workspace/lib/client.js (Junction → npx 缓存目录中的真实文件;浏览器经 createRequire(profiles/web) 解析加载该副本。)

已实证版本:DSH 0.1.0-rc.6(2026-08-14 构建)。 诊断工具:node scripts/patch-workspace-menu.mjs verify(逐区报告 ok / missing / ambiguous)。

升级后若 verify 报 missing,按本清单对照新版源码找到等价位置,修改 scripts/patch-workspace-menu.mjs 中对应 region 的 anchor(与 build 成对修改), 重跑单测(node --test test.mjs,含字节级往返 strip(apply(x)) === x)后再 apply

Region 与锚点

region作用锚点(rc.6 精确文本,缩进为 tab)
menuRegistry模块级菜单注册表(dshSessionMenuRegistry / dshRegisterSessionMenu / dshSubscribeSessionMenu / dshSessionMenuExtrasSnapshot工厂头部两条 require 行:let react = require("react"); + let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
slotDeclssidebar.workspaceschildren 声明 3 个 list 槽children: { "sidebar.workspaces.directoryFlow": {\n\t\t\t\t\tkind: "single",\n\t\t\t\t\tscope: "root"\n\t\t\t\t} },apply 内注册调用)
headerAction标题栏动作槽渲染(headerActions 最前)children: [wide && (0, react_jsx_runtime.jsx)(ViewOptionsMenu, {(7 个 tab 缩进)
nodeItemPropsSessionNodeItem 解构增加 renderSlotfunction SessionNodeItem({ node, currentId, now, onOpen, onRename, onFork, onArchive, drag, flat = false, t }) {(2 个 tab)
menuMerge「…」菜单合并 slot 条目(sessionMenuItems 末尾)archive 条目块(4 个 tab 起)+ \t\t\t];
menuSelectonSelect 分发 sessionMenu: 前缀动作onSelect: (id) => { 块(8 个 tab 起,含三条 if + },
sessionLead会话行首勾选框槽渲染(状态点前)children: [ + `(!flat
treePropsSessionTree 解构增加 renderSlotfunction SessionTree({ useSessions, startSession, ... setSessionOrder, t }) {(2 个 tab)
treeItemSessionTreeSessionNodeItemrenderSlotreturn (0, react_jsx_runtime.jsx)(SessionNodeItem, { 块(10 个 tab 起,onArchive: onSessionArchive, 结尾)
flatPropsFlatList 解构增加 renderSlotfunction FlatList({ useSessions, open, ... setSessionOrder, t }) {(2 个 tab)
flatItemFlatListSessionNodeItemrenderSlotreturn (0, react_jsx_runtime.jsx)(SessionNodeItem, { 块(6 个 tab 起,onArchive: onSessionArchive, + flat: true,
flatCallWorkspaceBrowser → FlatList JSX 调用传 renderSlot(透传链起点)}) : groupBy === "flat" ? (0, react_jsx_runtime.jsx)(FlatList, { + useSessions, + open,(6/7 个 tab)
treeCallWorkspaceBrowser → SessionTree JSX 调用传 renderSlot(透传链起点)}) : (0, react_jsx_runtime.jsx)(SessionTree, { + useSessions, + onSessionRename,(6/7 个 tab)
headerWidth标题栏动作容器放宽到容纳第 3 个按钮CSS 内联字符串:.qDHVXG_headerActions{opacity:1;visibility:visible;max-width:60px;(60px 保留 + 追加 96px,CSS 后者生效)
menuHostWorkspaceBrowser 根部隐藏容器挂载 sessionMenu 注册组件根 children 末尾:}) + ] + }); + } + //#endregion(5 个 tab 起)

机制要点

  • 每个 region 的插入内容完整包裹在 /* dsh-session-delete:region:<name>:begin */:end */ 之间, stripPatch 按标记外科式摘除,与文件版本解耦(单测保证字节级往返)。
  • checkPatch = 全部 15 对标记存在;applyPatchText 逐区校验锚点唯一命中后替换, 任一锚点缺失/歧义即整体拒绝写入(绝不写坏文件)。
  • 回归防线(test.mjs,18 用例):字节级往返 strip(apply(x)) === x;SlotCore 集成测试 (真实 slot 核心注册后断言 entry.children 含全部 4 槽);renderSlot, 出现次数断言 (9 处 = 2 原始解构 + 7 处透传接线);headerWidth 文本断言。
  • 渲染级演练(scripts/render-check.mjs,本地验证用):真实 React SSR 渲染补丁版 WorkspaceBrowser,断言三个槽出口全部触发——拦住"透传链缺口/渲染崩溃"类问题。
  • 写入用同目录 tmp + rename 原子替换;client-modules 按请求读文件且 cache-control: no-cache, 重载页面即取新内容。
  • 不要把目标物化为真实目录:dsh-app-boot.ensureSymlink 对真实目录直接抛错,Harness 无法启动。 补丁必须穿链写入(Windows 文件 I/O 自动解析 junction)。