Files
ycode/docs/expert-picker-source-20261016.md
T

75 lines
7.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 专家输入选择器恢复(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。