75 lines
7.5 KiB
Markdown
75 lines
7.5 KiB
Markdown
# 专家输入选择器恢复(2026-10-16)
|
||
|
||
本轮恢复原专家子菜单的实际组件体、搜索输入、选中/check/pin/召唤更多结构和 CSS,接入有类型的真实列表宿主。没有硬编码参考专家为可激活项目,不调用不存在的专家 API。主上下文负责专家 registry、会话激活、OMP 接线及主输入入口;本 worker 不改 ChatPane、ComposerControls、shared、main 或 App。
|
||
|
||
## 宿主接口
|
||
|
||
`src/renderer/src/capabilities/SourceExpertPicker.tsx` 默认导出泛型组件,导出 `ExpertPickerItem` 与 `SourceExpertPickerProps<T extends ExpertPickerItem>`:
|
||
|
||
```ts
|
||
interface ExpertPickerItem {
|
||
id: string
|
||
name: string
|
||
profession?: string
|
||
avatarUrl?: string // 浏览器可用的 http(s)/blob/data:image URL
|
||
description?: string
|
||
disabled?: boolean
|
||
searchText?: string // 若提供,按源契约为已经小写化的搜索缓存
|
||
}
|
||
interface SourceExpertPickerProps<T extends ExpertPickerItem> {
|
||
items: readonly T[]
|
||
selectedId?: string | null
|
||
busy?: boolean
|
||
error?: string
|
||
onSelect(item: T): Promise<void>
|
||
onManage(): void
|
||
onClose(): void
|
||
anchor: HTMLElement | null
|
||
scopeKey: string
|
||
}
|
||
```
|
||
|
||
传给 `onSelect` 的是当前宿主 `items` 中实际对象,保留额外 registry 字段,不从显示文字反造专家。重复 ID 只展示首个。名称严格使用原 `profession || name || id`;原搜索用小写 keyword 匹配 `searchText` 或显示名称,不额外发明 description 搜索。根可通过 `expertText` 把多语言字段投影为字符串。
|
||
|
||
原版是“+菜单→专家行→右侧子菜单”。`anchor` 应优先传专家菜单行,源码定位契约为 `right-start`、offset4、flip `left-start/right/left`、shift padding8。当前独立宿主传 composer 按钮也可运行,但入口位置是否与原版一致由根另验。依赖使用宿主已安装的 `@floating-ui/react 0.27.20`,原版包精确版本未知。
|
||
|
||
## 固定原版证据
|
||
|
||
WorkBuddy **5.8.2**,ASAR SHA-256 `035254bc76310ea46317433e4840602094543ef323d2d5c5aff7c131729de918`。本轮仅读取已保存 REA 导出,不操作原版窗口,不直接读取原版文件系统或 CDP。
|
||
|
||
JS 来源:`.tmp/rea-runtime-scripts.json`,Evidence `ev_717fa5e846e64d67ac19c8925d121bff632c0d3aefb3603b10858559cabb2dcb`。CSS 来源:`.tmp/rea-css-recovered/manifest.json`,Evidence `ev_377c8790468b3c67dad8577aabb327f98d3140659f0fffdbabfcff5a40cc9e94`。
|
||
|
||
| 文件 | 固定 SHA-256 | 恢复范围 |
|
||
| --- | --- | --- |
|
||
| wb-input-add-B045GnIg.js | `7842fa4321d5351bf6c822bbd0253e0d6d6e68cc9cfae3f2470b3d493c23daf4` | ExpertsSubmenu `[47192,49898)`、ExpertRow `[49899,50767)`、ExpertAvatar、SummonMoreIcon、显示名称和搜索 helpers |
|
||
| contexts-BMeWSUHk.js | `5f35b7489b107e21ef452c8ee88a95265756f6fc444841eef869228bbc44768b` | `wV` 原搜索 forwardRef `[4205837,4206556)`、`CheckIcon$2` `[4196249,4196837)`、`_V` base class map |
|
||
| zh-cn-Dfzn8myY.js | `05bdf17cc76e1c2547e84a2754d249405366eb5559149b1661837c9687e6efab` | 10 个 `input.wbAdd.experts.*` 中文原文,含暂无可用专家/未找到专家/召唤更多专家 |
|
||
| contexts-BkjwYSZT.css | `50cbd673f7f35fc7f966bdddc6c9f5677fdfe944cb904888d214619fca259380` | `_1mrhu_` 搜索/base 声明 |
|
||
| wb-input-add-CDNucW11.css | `07566131dac43d1854af1ecb973bf9736a63723a0786ba0d2d5287ed6f45f2f6` | `_14qob_` 专家子菜单声明 |
|
||
|
||
恢复脚本 `scripts/rea/recover-expert-picker.mjs` 先按上述固定 SHA 验证,再 AST 定位组件体、class map、中文字段。输出 `expert-picker-source.mjs/.d.mts`、`expert-picker-classes.json`、`expert-picker-source.css` 和 `expert-picker-manifest.json`。manifest 记录 10 个原体的 UTF-16 offset/body SHA 和所有生成文件 SHA。复用已经恢复的 `SkillSourceIcons` 中 Pin/Unpin/Search/Clear 字面 SVG,不改技能组件或样式。
|
||
|
||
## 保留与适配
|
||
|
||
保留 ExpertsSubmenu 的输入可见值与已提交查询两个状态、composition ref、composition end 提交、pin 事件 stopPropagation、选中正常条目只关闭、查询模式独立 selected 状态、空/加载失败/搜索失败状态、源搜索 Escape 清空并阻止外层关闭、check 和召唤更多结构。CSS 声明保持原值,仅加 `.yc-expert-picker` scope;原 panel 为 **240px**,条目 **32px**,avatar **16px**,搜索 **32px**,滚动列表 max-height **338px**。
|
||
|
||
原 normal 列表是 pinned + recent + 服务推荐补位,source qa=5、Ja=10。本机适配为真实可用 pinned + 最多5个额外 recent/宿主顺序条目,超过10行使用原 scrollList;搜索遍历全部真实 host items。没有云目录请求或填造推荐结果。原搜索 hook 的150ms timer仅用于网络 preload;本机已完整加载 registry,所以搜索过滤仍按源立即完成,不添加无意义网络延迟。
|
||
|
||
pin/recent 使用 `ycode.experts.menu.v1:<scopeKey>`。根须把实际账户/空间/会话边界编码入不透明 scopeKey;不自行推测账户。未知/移除 ID 不产生可激活的 unresolved 假行。读取 memory 验证数组和字符串,localStorage 不可用不会阻断激活。
|
||
|
||
原正常条目的 onSelect 为同步后立即 close,搜索召唤可异步。本机真实 activation 是 Promise,因此只在成功后关闭;同步 ref 阻止双击、busy 和 disabled 条目,失败显示明确宿主错误并保留重试。scope 或组件销毁后,旧 Promise 不写新 scope memory、不关闭新选择器。宿主本身仍负责激活事务/取消和实际会话所有权;组件无法撤销已经发给宿主的任务。
|
||
|
||
原 ExpertsSubmenu/父 WbInputAddMenu 没有 Arrow 上下行遍历;父浮层处理 Escape,搜索自己处理非空 Escape。本机直接宿主补 tabindex、禁用行跳过、上下/Home/End、Enter/Space、打开聚焦搜索及关闭返回 anchor,明确列为 host adaptation。`ExpertRow.disabled` 增加 item.disabled;source body 此外只替换运行时绑定。源子菜单 CSS 自身没有动画;父“+”菜单有 `.18s` pop-in。本轮不把父动画误加为子菜单独立动效,不声称整个输入菜单动效已等价。
|
||
|
||
Avatar 底层是浏览器安全 URL/首字母 fallback,Tooltip 为原生 title;两者不是原版通用 primitive 的完整恢复。暗色、云推荐、完整+菜单入口、头像 fallback paint、tooltip 动画/延迟、触屏边界与极小视口仍需继续 REA 对标。
|
||
|
||
## 验证与交付
|
||
|
||
- `node scripts/rea/recover-expert-picker.mjs`:恢复;`--check`:固定 **5 个源 SHA、10 个原体、10 个中文 label、5 个输出** 检查通过。
|
||
- `node scripts/rea/test-expert-picker-native.mjs`:**39/39 PASS**,`.tmp/expert-picker-native-iFW4nG/report.json`;1052×901普通可见 Electron + SwiftShader,真实组件和受控 typed host,不用 fake IPC,也不访问原版。
|
||
- `npm run typecheck`:node/web 全通过;根负责生产 build 和实际 registry/OMP 集成。
|
||
|
||
原生局部尺寸:anchor `[400,600,100,32]` 时 panel `[504,600,240,273]`,row32、avatar16、search `[224,32]`;全池12项查询滚动高度338;右边缘 anchor x900 时翻转 panel x656、width240。验证还覆盖 selected 不重复激活、disabled、大小写/IME/两段 Escape、scope pin/recent、typed item 附加字段、延迟成功关闭、防重复、失败保留、旧 scope Promise 隔离、busy、召唤更多与空/错误原文。
|
||
|
||
这些几何断言根据固定源 CSS/源码计算并验证宿主生效,**本轮没有原版同状态 runtime 截图或像素比较**,不宣称整个专家菜单或全状态 1:1 完成。原生截图和失败状态截图在上述报告目录,原版源码体与生成 SHA 在 manifest。
|