Files
ycode/docs/安装中心模块拆解-2026-10-17.md
T

762 lines
37 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-17)
> **范围订正:本文件不再是当前实施任务。** 用户已明确第18项是“设置 → 安全中心”,此前按应用安装管理理解有误。本文件保留历史证据与分析,不作为安全中心的需求、实现方案或完成度。当前入口见[安全中心范围订正与待拆解项](安全中心模块拆解-2026-10-17.md)。已有发现应用功能保留;下文安装/更新/卸载等批次不再列入本次四模块计划。
## 文档范围与结论
本文只做模块拆解、证据归档和分批实施方案,不实现业务代码,不触发安装、更新、卸载、授权或保存。本文形成后通过 REA 对 WorkBuddy 5.8.3 做了一次只读 target 枚举、一次无操作的声明式探针,以及一次打开设置窗口的声明式探针尝试;没有执行产品写操作,也没有修改 REA 配置。
**当前结论:**
- 既有 REA 证据已经证明 WorkBuddy 5.8.3 侧栏“发现应用”浮层的入口、稳定打开态、主要几何、CSS 和客户端请求/授权逻辑。
- 既有证据**没有**采集“设置 → 应用管理/安装中心”的懒加载主页面。现有脚本清单只出现 `BuddyAppsPanel-vC0qX_Oo.js` 和 `BuddyAppsPanel-OzkcFEe0.css` 的文件名,没有这两个资源的正文。
- 2026-10-17 的最新 REA 枚举只返回主窗口 `1CAD78026104DDABDB43F9EB6BA7635D`,没有设置窗口 target。一次无操作声明式探针成功(`ev_a3ca56f518f5c5101d2ae6e64f24794a564956da643c11e622c56b5cbb245000`),但没有导航。
- 打开设置窗口的声明式探针被 REA 以 `invalid_request / invalid_input` 拒绝,未产生 Evidence ID、设置 target 或 `data-settings-tab="buddyApps"` 页面。这次结果只记为工具输入失败,不能反推 WorkBuddy 没有应用管理页,也不能反推 REA 不支持该动作。
- “发现应用”是应用切换/发现浮层,不能据此推定安装中心主页面的列表、已安装状态、版本、更新、卸载、授权按钮和失败恢复。
- YCode 当前只有同壳适配的本地“发现应用”浮层,映射到专家、技能、连接器三个本地能力入口;没有云应用目录、应用详情、安装/更新/卸载、授权、依赖安装或应用管理主页。
- 因此 TODO 18 只能保持“部分实现”。本轮不能把它标记为完成,也不能把浮层通过当作安装中心 1:1 验收。
本文证据标签:
| 标签 | 含义 |
| --- | --- |
| `REA-RUNTIME` | REA 运行时观察到的页面、DOM、布局、视觉或声明式输入结果 |
| `REA-STATIC` | REA 保存的 renderer script/CSS/manifest 正文静态结论 |
| `YCODE-SOURCE` | 当前 YCode 源码事实 |
| `INFERENCE` | 基于证据的工程建议,不能当成原版事实 |
## REA 证据清单
目标版本均为 WorkBuddy 5.8.3,Windows,Chrome 138 / Electron 37.10.3。主要观察在暗色主题、`1336×1240` 主窗口或 `900×680` 设置窗口下完成。
| 用途 | Evidence ID | 保存位置 | 时间(UTC) | 观察范围与边界 |
| --- | --- | --- | --- | --- |
| 主窗口基线 | `ev_ab93f4313af45f559597bfa886f218257edb9b8c1c1c056c446b2ed26a2352e9` | `.tmp/rea-todo18-main-visual.json`、`.tmp/rea-todo18-main/` | `2026-10-17T05:44:14.389Z` | 暗色主窗口、1336×1240、无浮层的基线。截图 SHA-256 `b561129cfa37a5b6220e449fd13de7eadc2bc88b68cf48b5c647052aff4a8591`。不能证明打开态。 |
| 设置窗口基线 | `ev_5b635ae361c0988fa459b5d58897d40ab52ae2e814394b8c21080d1eb9bcb6a1` | `.tmp/rea-todo18-settings.json`、`.tmp/rea-todo18-settings/` | `2026-10-17T05:44:00.912Z` | 暗色设置窗口、900×680,停在“记忆与进化”。截图可见“数据与安全”分组下的“应用管理”导航,但右侧不是应用管理页。截图 SHA-256 `5fe5eb779151e04e1415198cd5e3a2958f02395381cc743713f3cddf9961bc3c`。 |
| 打开后复核 | `ev_43e8726c4cfac93184509ea30ae0d1305f4ad9c4a186f6ce7a20a7b16810316c` | `.tmp/rea-todo18-discover-after.json`、`.tmp/rea-todo18-discover-after/` | `2026-10-17T05:45:42.851Z` | 截图 SHA 与主窗口基线完全相同,画面未出现浮层。它不能作为“发现应用”打开态证据。 |
| 键盘打开过程 | `ev_d3527391f609e4a8cb4d194a24ee17dcbbdfc0a2d58db240ef3686119694d85f` | `.tmp/rea-todo18-discover-key.json`、`.tmp/rea-todo18-discover-key/` | `2026-10-17T05:49:07.439Z` | REA 对 `.industry-template-switcher__trigger` 执行 Enter,动作完成并等待 500ms;`frame-000.png` 显示浮层。最终截图 SHA `65f7ce3cd1d81f4f01f9fabe745b50c0236831f55e69b2012f0fe4e2135271cc`。只证明入口可打开,不证明搜索、选择、滚动到底和授权。 |
| 稳定打开态 | `ev_bd22e46c95d3887daba16dbe319389ad74e10afea8f71af9a7639e8bce95ebb4` | `.tmp/rea-todo18-discover-state.json`、`.tmp/rea-todo18-discover-state/` | `2026-10-17T05:49:49.145Z` | 暗色浮层稳定截图 SHA-256 `f5284085280418769f8c6f022c1e2451f167815783227373c2a90d766ea2bd40`。含布局树,但 REA 布局不含文本/input value,应用名称与描述需结合同次截图。 |
| renderer 脚本源 | `ev_2b8db4eb73c59a8d3d80c3e37db5ea9b5bf1d13390d5238d81ff2cc53d11dc09` | `.tmp/rea-todo18-main-scripts.json`;恢复件 `.tmp/rea-todo18-matches/contexts-DgzzFjnf.js` | 采集于 2026-10-17 | REA 捕获 321 个当前已加载脚本。`contexts-DgzzFjnf.js` 为 7,553,508 bytes,SHA-256 `8d0c375f141cf724c7f77233ee1d54dd21c9cc86286b79d119711f34a6236746`。其中包含发现浮层、API、登录、consent、依赖和缓存逻辑。 |
| 样式源 | `ev_7eb66ea8d5949eb7d872f1a93a97894a811b3beb7a02eabd81a500409f1045e4` | `.tmp/rea-todo18-styles-current.json`、`.tmp/rea-todo18-current-contexts.css`、`.tmp/rea-todo18-industry.css` | 采集于 2026-10-17 | `contexts-BkjwYSZT.css` 为 1,600,789 bytes,SHA-256 `50cbd673f7f35fc7f966bdddc6c9f5677fdfe944cb904888d214619fca259380`。恢复出的行业浮层规则文件为 21,085 bytes,SHA-256 `ab1771d8109a137d566e19d24901fa088f893354553900172e5719684de58a5d`,只是原 CSS 的子集。 |
| 当前 target 枚举 | `ev_2504239bed6d570c1e1e274465ffb9989058ba81ea503f7b295db6add4e380f1` | `.tmp/rea-four-modules-install-targets.json` | 采集于 2026-10-17 | WorkBuddy 5.8.3 / Electron 37.10.3;只枚举到主窗口 target `1CAD78026104DDABDB43F9EB6BA7635D`,没有设置窗口。 |
| 无操作探针确认 | `ev_a3ca56f518f5c5101d2ae6e64f24794a564956da643c11e622c56b5cbb245000` | `.tmp/rea-four-modules-install-probe-minimal.json` | `2026-10-17T10:04:39.891Z` | 使用仅含 wait 的 REA 声明式探针;`probe.status=completed`,0 个探针帧。视觉 viewport 为 `1336×902`,PNG SHA-256 `d6ef3903bee943b69272a003d8ac7753e7bef882d4949d10104ccac06f70115f`。没有点击、导航或设置窗口证据。 |
| 打开设置探针失败 | 无;工具拒绝后未生成 Evidence ID | `.tmp/rea-four-modules-install-open-settings.json`、`.tmp/rea-four-modules-install-open-settings-retry.json` | 2026-10-17 | 两个文件均 295 bytes;返回 `code=invalid_request`、`category=invalid_input`、`message=Analysis input is invalid. Check the arguments and try again.`。没有证据表明点击已执行;失败后停止重试。 |
### 证据边界
1. 没有安装中心主页面 DOM、视觉、CSS 或 lazy chunk 正文。
2. 没有“应用管理”导航的实际点击记录;当前截图只证明导航文字可见。
3. 没有真实 catalog API 响应、账号/企业 header、登录跳转结果或 consent 页面截图。
4. 没有安装、更新、卸载、重装、取消、失败、重试或部分成功的产品运行态。
5. 没有浅色主题下的原版“发现应用”稳定截图;当前浅色验收来自 YCode 自身。
6. REA DOM/layout 会省略文本和输入值,不能从布局节点单独证明中文文案。
7. 运行时截图与 DOM/layout 是顺序观察,不是同一原子帧。
8. 最新打开设置窗口探针在 REA 参数校验阶段失败;没有设置 target、`buddyApps` active 状态或主页面截图。
9. `BuddyAppsPanel-*` 是否已在当前窗口加载仍未证明;没有打开主页面就不能把“未观察到”写成“不存在”。
## 可用入口与选择器
### 设置主页面入口
`REA-STATIC` 已从保存的 renderer 正文确认设置导航项稳定带有 `data-settings-tab`:
```css
[data-settings-tab="buddyApps"]
.settings-navigation__item[data-settings-tab="buddyApps"]
.settings-navigation__item--active[data-settings-tab="buddyApps"]
```
设置窗口外层可用的稳定选择器:
```css
body.settings-window
.settings-window-root
.settings-modal__nav
.settings-navigation
.settings-modal__content
.settings-modal__panel
```
现有证据截图对应“应用管理”的导航行,但页面未打开。主协调补采时建议:
1. 选择设置窗口自己的 REA target。历史设置 target 为 `8E8A75786E23EA4A57CD049223F7099D`;当前主窗口 target `1CAD78026104DDABDB43F9EB6BA7635D` 不能默认代表设置窗口。
2. 点击 `button[data-settings-tab="buddyApps"]`。
3. 等待 `.settings-navigation__item--active[data-settings-tab="buddyApps"]`。
4. 再等待 500–1000ms,确保 `BuddyAppsPanel-vC0qX_Oo.js` 与其 CSS 懒加载完成。
5. 因主页面根 class 尚未知,先使用 `.settings-modal__panel`、`.settings-modal__content` 和 `.settings-modal__panel > *` 记录页面边界,不要先假定 `.buddy-apps-panel`。
6. 同一次 lifecycle 同时采集视觉、script sources 和 style sources;只采稳定页面,不点击安装、更新、卸载或授权动作。
### 发现应用浮层
`REA-RUNTIME` 与 `REA-STATIC` 共同确认的稳定选择器:
```css
.industry-template-switcher__trigger
.industry-template-switcher__trigger--general
.industry-template-switcher__trigger--application
.industry-template-switcher__reset-button
.industry-template-switcher__popover[role="dialog"]
.industry-template-switcher__panel
.industry-template-switcher__search-header
.industry-template-switcher__search
.industry-template-switcher__search .wb-input__inner
.industry-template-switcher__list
.industry-template-switcher__group
.industry-template-switcher__group-items
.industry-template-switcher__item[data-template-id]
.industry-template-switcher__item-action-btn
.industry-template-switcher__retry
.industry-template-switcher__more
.industry-template-switcher__back
.industry-template-switcher__recent-grid
.industry-template-switcher__empty
```
说明:
- `data-template-id` 在运行时实际承载 `applicationId` 值。
- 选中项在原版是 `role="option"` 的非按钮 `div`,未选中项是可点击 `button`。
- 不应依赖样式哈希类名 `src-*` 或 `_tag_*`,这些类名跨构建不稳定。
## 原版可证行为
### 1. 功能开关、登录与入口
`REA-STATIC`:
- 设置路由 `buddyApps` 由 feature flag `buddyAppEnabled` 控制是否可见。
- 发现应用根据账号、API route 和 feature flag 决定是否出现。
- 未登录时点击打开入口会先走登录,不会直接展示云目录。
- API route 分个人与企业两种;企业路线把 enterprise id 编入路径。
`REA-RUNTIME`:
- 暗色主窗口侧栏顶部存在“发现应用”胶囊入口。
- 当前截图中的入口是通用态,文案“发现应用”,不是已选中某个业务应用的状态。
### 2. 浮层结构与分组
`REA-RUNTIME` 稳定打开态:
| 结构 | 实测 |
| --- | --- |
| 触发按钮 | `[173.28125,48,98,28]`;12/500/20;暗色背景 `rgb(46,46,46)`;圆角 100px |
| 浮层 | `[31,82,240,420]`;固定定位;padding 8;圆角 16;暗色背景 `rgb(36,36,36)` |
| 内面板 | `[40,91,222,402]` |
| 搜索区 | `[40,91,222,33]`,输入框 `[40,91,222,28]` |
| 列表视口 | `[40,128,222,365]`;gap 4;纵向滚动 |
| 推荐组 | 标题高 24,条目列表高 960;按 48px 行高可容纳 20 项后继续滚动 |
| 条目 | 218×48;padding 8;gap 12;圆角 8 |
| 图标 | 24×24;列表中圆形,暗色背景 `rgb(41,41,41)` |
| 标题/描述 | 13/16、11/14;描述为 50% 暗色文字 |
当前截图可见的推荐样例为“通达信、企鹅教师助手、美图设计室、腾讯自选股、腾讯电子签AI合同助手、Alpha派 Lite、广发证券”。这些是随账号/服务变化的运行时数据样例,**不得写死为 YCode 目录契约**。
### 3. 列表、搜索和分页
`REA-STATIC`:
- `recent` 与 `recommended` 各按场景请求 20 项。
- 默认只展示 recent 前 6 项;recommended 会过滤掉已在 recent 中出现的 `applicationId`。
- recent 超过 6 项或 `hasMore` 时有“更多”,进入独立 recent 网格视图并可返回。
- 非搜索模式滚动到距底部 80px 内时调用对应场景的 `loadMore()`。
- 搜索输入有 250ms debounce;搜索模式隐藏 recent/recommended 分组,只显示搜索结果。
- 搜索有 loading、error/retry、空结果非搜索和搜索无结果状态。
- 请求使用 owner key 隔离个人/企业账号;旧请求有 generation guard。
`REA-RUNTIME` 只覆盖默认非空推荐列表;上述分页、搜索、错误和空态属于代码事实,未逐态截图。
### 4. 条目身份与选择
列表 summary 的核心字段来自 `REA-STATIC`:
```ts
interface BuddyApplicationSummary {
applicationId: string
name: string
description?: string
icon?: string
operationTag?: {
title: string
description: string
}
}
```
条目行为:
- 未选中行悬停/聚焦显示“进入”动作;选中行显示品牌色对勾与“退出”。
- 选中项由当前应用/模板选择状态决定,不由列表自带 installed 布尔值决定。
- 点击未选中 summary 后,浮层先关闭,再请求 detail。
### 5. 应用详情、激活与授权
`REA-STATIC` 证明的 detail 字段:
```ts
interface BuddyApplicationTemplate {
templateId: string
applicationId: string
name: string
templateName: string
description?: string
category?: string
operationTag?: { title: string; description: string }
icon?: string
schemaVersion: number
templateVersion: number
versionNo: number
requiredScopes: string[]
allowedOrigins: string[]
templateConfig: unknown
releaseNote?: string
publishedAt?: string
}
```
上面的 `templateConfig` 在实际代码里还有 schema 校验;这里保留为 `unknown`,避免把未经原文逐项恢复的完整 schema 当成 YCode 契约。
选择流程:
1. 请求 detail。
2. 等待本地选择状态 hydrated,最长 8s。
3. 校验账号在异步过程中没有切换。
4. 调登录/授权状态接口,取得 `authorized`、application、redirect URI 和 granted scopes。
5. 已授权则直接提交本地模板上下文。
6. 未授权则显示 consent;用户可批准或跳过跳转。
7. consent 后获得一次性 code 和 granted scopes。
8. 根据模板配置安装/连接 MCP 依赖,并可能打开外部 authorization URL。
9. 成功后提交模板选择、上报 usage、触发 onboarding,并返回主页。
10. 退出当前应用时清空选择,并尝试移除该应用的 MCP dependency。
全局同一时间只允许一个应用切换流程,避免并发授权。
### 6. 远程 API 事实
`REA-STATIC` 中可确认的个人账号端点:
| 功能 | 方法 | 路径/参数 |
| --- | --- | --- |
| 场景列表 | GET | `/api/v1/open-platform/buddy_application?limit={limit}&scene={recent\|recommended}[&cursor=...]` |
| 搜索 | POST | `/api/v1/open-platform/buddy_application/search`,body `{ keyword }` |
| 详情 | POST | `/api/v1/open-platform/buddy_application/detail`,body `{ application_id }` |
| 使用上报 | POST | `/api/v2/open-platform/asset-usage/report`,body `{ asset_id, asset_type: "buddy_app" }` |
| 入口可用性 | GET | `/api/v2/open-platform/buddy/entrance` |
企业账号使用 `/v2/enterprises/{enterpriseId}` 前缀和对应子路径。
列表响应可确认字段包括 `applications`、`has_more`、`next_cursor`。请求会按需附加 `X-GPU-DEVICE-NAME`。
**目前没有证据证明以下接口:**应用包下载、安装、更新、卸载、版本检查、安装进度、取消、回滚、权限撤销、已安装列表。不能用上述 discovery/usage 端点臆造完整安装 API。
### 7. 设置页中的应用管理
`REA-STATIC` 已确认:
- 设置 route id 为 `buddyApps`。
- 入口是 `button[data-settings-tab="buddyApps"]`,中文截图显示“应用管理”。
- 页面是懒加载 `BuddyAppsPanel-vC0qX_Oo.js`,配套 `BuddyAppsPanel-OzkcFEe0.css`。
- route 可用性受 `buddyAppEnabled` 控制。
**尚不能确认:**
- 主页面标题、分组、搜索、筛选和排序。
- 是否显示市场目录、已安装应用或两者共存。
- installed 的判定规则,以及安装与应用激活是否同一概念。
- 版本、更新提示、自动更新、更新检查、发布说明。
- 安装、更新、卸载、打开、停用、退出、重试、取消的入口和确认方式。
- loading、empty、error、partial、offline、unauthorized、dependency-missing 状态。
- 主页面的所有几何、深层深浅主题和动画。
这是主协调下一步最优先的 REA 补采目标。
2026-10-17 补采结果:
- 设置窗口 target 不在当前 REA endpoint 的 target 列表中,只有一个主窗口。
- 计划中的 `open-account-menu → open-settings-window` 探针没有进入动作生命周期;REA 在输入校验阶段返回 `invalid_request / invalid_input`,因此没有 Evidence ID 和声明式动作步骤。
- 没有采集 `button[data-settings-tab="buddyApps"]`、`.settings-navigation__item--active[data-settings-tab="buddyApps"]` 或 `.settings-modal__panel` 的主页面内容。
- 本专项按用户要求停止重复尝试。安装中心主页面的布局、状态、版本更新、卸载和错误恢复仍为明确未知,等待后续设置窗口 target 和新 Evidence 补证。
## YCode 当前状态
### 已实现
| 能力 | 状态 | 主要源码 |
| --- | --- | --- |
| “发现应用”入口与浮层 | 已实现可交互壳 | `src/renderer/src/components/AppDiscoverPopover.tsx` |
| 浮层几何、搜索、空态、键盘、外部点击、焦点恢复 | 已实现本地版本 | 同上、`app-discover-popover.css` |
| 最近使用 | 已实现 localStorage 版,最多 6 个本地能力 ID | `ycode.app-discover.recent.v1` |
| 应用选择 | 映射到 experts / skills / connectors 三个本地能力页 | `Sidebar.tsx`、`App.tsx`、`CapabilityCenter.tsx` |
| 选中态退出 | 从本地能力页回到聊天 | `AppDiscoverPopover` 的 `onExit` |
| 本地能力 | 专家、本地技能、自定义 MCP 已有各自页面和数据层 | `src/renderer/src/capabilities/` |
### 占位
| 能力 | 现状 |
| --- | --- |
| 技能市场 | 技能页对未连接目录显示本地空态,可导入本地技能 |
| 连接器目录 | 当前以自定义 MCP 为主,云目录和第三方 OAuth 未接 |
| 最近使用 | 只保存本地三个 capability ID,不是原版账号级应用使用历史 |
| 应用图标 | 使用本地 SVG,不是远端应用图标和失败 fallback |
### 缺失
| 能力 | 缺口 |
| --- | --- |
| 安装中心主页面 | 完全缺失;设置导航中 `buddyApps` 还被用户明确移除 |
| 云应用目录 | 无列表、搜索、detail、最近、推荐和分页 API |
| 应用身份模型 | 无 `applicationId/templateId/version/scopes` 数据 |
| 安装状态机 | 无 installed/installing/updating/uninstalling/failed |
| 安装来源 | 无市场、企业、URL、本地包或内置来源模型 |
| 更新与版本 | 无版本比较、release note、更新检查 |
| 卸载与恢复 | 无卸载确认、部分失败、重试、回滚 |
| 授权 | 无 login、consent、scope grant、redirect URI |
| 应用依赖 | 无应用级 MCP dependency 安装/移除 |
| 使用上报/onboarding | 无 usage report、show observer、onboarding 状态 |
| 管理入口 | `SettingsDialog.tsx` 的 `REMOVED_SETTINGS_TABS` 包含 `buddyApps` |
### 需要先决定的产品边界
用户此前要求移除“系统设置 → 应用管理”入口。若后续恢复安装中心,不应静默推翻该决定。可由主协调确认采用下列之一:
1. 保留设置入口移除,只在侧栏“发现应用”中增加管理/浏览入口。
2. 恢复“应用管理”设置页,同时保留“发现应用”作为切换器。
3. 将两者合并为独立安装中心页面,设置与侧栏都指向同一路由。
本拆解建议先按“两个表面、一个状态源”设计:发现浮层负责快速发现/切换,安装中心管理页负责目录、安装、版本、授权和卸载;两侧共享同一 registry,避免出现两套 installed 状态。
## 建议数据契约
以下是 `INFERENCE`,用于 YCode 后续实现;字段名尽量贴近 REA 静态事实,但不冒充原版完整 schema。
```ts
type BuddyAppSource = 'builtin' | 'marketplace' | 'enterprise' | 'local'
type BuddyAppAvailability = 'available' | 'unavailable' | 'entitlement-required'
type BuddyAppLifecycle =
| 'not-installed'
| 'installing'
| 'installed'
| 'active'
| 'updating'
| 'update-available'
| 'uninstalling'
| 'failed'
| 'unauthorized'
| 'dependency-missing'
interface BuddyAppSummary {
applicationId: string
templateId?: string
name: string
description?: string
iconUrl?: string
operationTag?: { title: string; description?: string }
source: BuddyAppSource
availability?: BuddyAppAvailability
}
interface BuddyAppDetail extends BuddyAppSummary {
name: string
versionNo: number
templateVersion?: number
schemaVersion?: number
category?: string
requiredScopes: string[]
allowedOrigins: string[]
templateConfig: unknown
releaseNote?: string
publishedAt?: string
}
interface BuddyAppRegistryEntry {
applicationId: string
templateId?: string
installedVersion?: number
availableVersion?: number
lifecycle: BuddyAppLifecycle
source: BuddyAppSource
installedAt?: number
lastOpenedAt?: number
lastError?: string
operationId?: string
dependencies: BuddyAppDependencyState[]
}
interface BuddyAppDependencyState {
kind: 'mcp' | 'connector'
key: string
state: 'missing' | 'installing' | 'connected' | 'needs-auth' | 'error'
error?: string
}
interface BuddyAppOperation {
operationId: string
applicationId: string
kind: 'install' | 'update' | 'uninstall' | 'activate' | 'deactivate'
phase: 'queued' | 'downloading' | 'verifying' | 'applying' | 'authorizing' | 'connected' | 'done' | 'failed' | 'cancelled'
progress?: number
message?: string
startedAt: number
finishedAt?: number
}
```
工程约束:
- `applicationId` 与 `templateId` 分开;现有原版列表以 `applicationId` 去重。
- 版本、scope、origin、redirect URI 必须保存快照,避免更新过程中配置变化。
- installed、active、authorized、dependency-ready 必须分开。
- operationId 用于 UI 去重和恢复;不能只靠 loading 布尔值。
- token、authorization code、secret 不进入 renderer 持久状态或日志。
## 本地功能与远端依赖边界
| 能力 | 本地可完成 | 依赖远端/宿主 |
| --- | --- | --- |
| 浮层/主页面布局 | 是 | 否 |
| 列表缓存、最近使用、当前选择 | 是 | 初次目录数据需要远端 |
| 本地 registry 和 operation journal | 是 | 状态变更需要服务端确认 |
| 目录列表、搜索、详情 | 否 | 是 |
| 登录、consent、scope grant | 否 | 是 |
| 应用包下载、校验、安装、更新、卸载 | 否 | 是;若 YCode 自建安装包生态则另立本地协议 |
| 应用模板 config 和 allowed origin | 可缓存 | 更新源来自远端 |
| MCP dependency 本地注册 | 是 | 授权/远端 connector 仍可能需要服务端 |
| usage report、show/click telemetry | 可本地排队 | 上报需要远端 |
| entitlement、企业策略、配额 | 否 | 是 |
| 错误文案和恢复 UI | 是 | 具体 reason code 来自宿主/服务端 |
| 安装 provenance/checksum | 可实现本地校验器 | 可信摘要/签名来源需可信配置 |
原则:没有真实安装结果时,UI 只能显示“未接入/等待服务”,不能显示“安装成功”。
## 建议模块拆分
### A. `buddyAppCatalog`
职责:
- recent/recommended/search/detail。
- 500ms 内搜索 debounce 的内部实现可沿用 250ms 事实,但需要统一 abort/generation。
- 账号、企业、feature flag 作为请求 key。
- summary/detail 校验、去重、缓存和 stale 响应丢弃。
不负责安装状态。
### B. `buddyAppRegistry`
职责:
- 已安装列表、版本、来源、最近打开时间。
- selected application/template。
- install/update/uninstall/active 状态。
- 操作日志、错误和恢复。
本地 registry 必须可以独立启动;远端 catalog 失败不能让已安装应用消失。
### C. `buddyAppInstaller`
职责:
- 下载、完整性校验、解包/安装、原子切换、失败回滚。
- operation progress/cancel。
- 安装来源差异。
此模块是否存在原版真实包安装流程目前未知;不得把“安装 MCP dependency”改名为“安装应用”。
### D. `buddyAppAuthorization`
职责:
- login/authorized 状态。
- consent、scope diff、grant。
- redirect/MCP 授权的衔接。
- 账号切换取消未完成操作。
### E. `buddyAppUi`
包含两个 surface:
- switcher:快速发现、最近、推荐、搜索、切换/退出。
- manager:已安装、目录、版本、更新、卸载、授权、依赖、错误恢复。
两者共享 Registry/Store,但各自保留 surface-specific UI state。
### F. `buddyAppObservability`
- 展示曝光、点击、进入、consent、授权失败、usage report。
- 事件失败不能破坏业务主流程。
- 脱敏 app id/version,不记录 token/code/secret。
## 分批任务与验收标准
### 批次 0:补采应用管理主页面
范围:
- 主协调通过现有 REA lifecycle,在设置窗口点击 `[data-settings-tab="buddyApps"]`。
- 同次 capture 开启 scripts、styles、visuals。
验收:
- 捕获到 `BuddyAppsPanel-vC0qX_Oo.js` 正文或其新的 build hash。
- 捕获到 `BuddyAppsPanel-*.css` 正文。
- 新 Evidence ID、target、captured_at、script/CSS SHA-256、viewport、theme 全部记录。
- 产出主页面 DOM/layout/稳定截图,至少覆盖默认稳定态。
- 明确没有触发安装、更新、卸载、授权等有副作用动作。
当前状态:**已尝试,未完成。** 最新 target 枚举只有主窗口;打开设置窗口的探针在 REA 参数校验阶段失败,没有设置 target。批次 0 未通过,阻塞条件正是设置页面 source/lifecycle,而不是已有静态结论不足。
取消条件:
- 只采到导航 active class,未加载 lazy chunk。
- 只采到 `.settings-modal__panel` 但内容仍为其他设置页。
### 批次 1:数据契约与只读 registry
范围:
- 建 `BuddyAppSummary/Detail/RegistryEntry/Operation/Dependency` 类型。
- 建立按账号/企业隔离的本地 registry。
- 无远端时显示真实“目录未连接”,已安装本地条目仍可展示。
验收:
- ID 身份稳定;同 application 不会因 template 版本重复成多张卡。
- 本地 registry 跨重启保留。
- account/enterprise 切换不会串数据。
- 没有真实 installed 数据时不伪造 installed 状态。
### 批次 2:应用管理页壳与本地状态
范围:
- 安装中心主页面骨架、搜索、筛选、分组。
- 列表、空态、加载态、错误态和 operation banner。
- 配置入口决定:独立页或恢复设置入口由主协调拍板。
验收:
- 在 900×680 设置窗口和主窗口布局无溢出。
- 浅色/深色、正常/窄宽、空/错/loading 可稳定渲染。
- `[data-settings-tab="buddyApps"]` 或替代入口的导航语义明确。
- 不依赖云端即可打开本地 manager shell。
### 批次 3:目录列表、搜索和详情
范围:
- recent/recommended/search/detail adapter。
- summary 去重、分页、stale guard、请求取消。
验收:
- 空查询、250ms 搜索、无结果、失败重试、下一页、末尾停止。
- recent 与 recommended 去重。
- account/enterprise 切换取消旧请求。
- 远端不可达时返回可恢复错误,不显示空目录冒充成功。
### 批次 4:安装/激活状态机
范围:
- `not-installed → installing → installed → active` 等状态。
- 同一 application 的并发操作锁。
- failure、retry、cancel、app restart 恢复。
验收:
- 双击安装只产生一个 operation。
- UI 进度来自 operation 状态,不由定时器模拟。
- 失败不会部分标记 installed。
- 重启后未完成操作可查询、恢复或明确标记未知。
- “安装应用”与“安装 MCP dependency”在产品文案和状态上分开。
### 批次 5:更新、卸载与恢复
范围:
- 版本比较、release note、确认流程。
- 卸载对 active 应用、MCP dependency、云端授权和本地数据的影响。
验收:
- 同版本、旧版本、新版本、降级、unknown version均有明确状态。
- 更新失败回滚到旧版本和旧 selected template。
- 卸载前明确是否保留本地数据与授权。
- 卸载失败可重试,不把卡片直接删掉。
### 批次 6:登录、consent、scope 和依赖授权
范围:
- login/authorization adapter。
- consent summary、scope diff、取消、拒绝、跳转失败、回到桌面。
- MCP/builtin/custom/joint auth 分支。
验收:
- 账号切换时取消旧流程。
- redirect URI、scopes、template version 在授权期间发生变化则拒绝提交。
- 取消/失败不会写入 ready 状态。
- code/token 不落盘、不打印。
- 依赖失败与应用安装状态可区分。
### 批次 7:像素与全状态验收
范围:
- switcher 与 manager 的原版同数据、同主题、同尺寸对照。
验收:
- 入口、popover、manager 默认态在浅/深色完成截图和几何比对。
- 搜索、loading、error、empty、scroll、load-more、hover、focus、selected、disabled。
- 安装、更新、卸载、授权、依赖、失败、重启恢复。
- 键盘、focus trap、Escape/外部点击、IME 和窄窗。
- 不以 YCode 专项 PASS 代替 WorkBuddy 同状态 1:1。
## 精确未知项
### 主页面与产品信息架构
1. 设置“应用管理”和侧栏“发现应用”是否共享同一个应用实体、选择状态和 installed 列表。
2. 主页面是否只管理已安装应用,还是也展示市场目录。
3. 主页面标题、分组、筛选、排序、搜索和详情进入方式。
4. 是否支持企业目录、内置应用、本地应用和第三方 market 的混合列表。
### 安装语义
1. “安装”是否下载本地包,还是只创建账号授权/云端绑定。
2. 安装与应用“进入/激活”是否同一操作。
3. 安装成功后是否立即成为当前应用,还是仍展示“进入”。
4. 同一 application 是否可安装多个 template/version。
### 更新语义
1. 更新源、版本比较规则和自动/手动检查时机。
2. 更新通知显示位置、release note 来源和强制更新规则。
3. 更新中能否使用当前版本,失败时是否回滚。
### 卸载语义
1. 卸载按钮的确认文案和危险色层级。
2. 本地数据、云端 grant、MCP dependency、recent snapshot 是否一起清除。
3. active 应用或 dependency-disconnected 状态下的卸载限制。
### 状态与错误
1. 完整状态枚举和 reason codes。
2. 进度是否支持百分比、字节数、阶段文案。
3. 取消、超时、断网、配额不足、企业策略、权限撤销、依赖失败的实际文案。
4. 失败后 operation 是否保留、恢复或可重试次数。
### 数据与持久化
1. 本机 registry 的 storage key、schema version、账号/企业隔离。
2. 已安装包位置、完整性校验、签名和升级目录。
3. recent/show/usage 的服务端与本地双层缓存。
4. 应用图标 URL、缓存、CSP 和失败 fallback。
### 视觉
1. “应用管理”主页面完整 DOM/CSS、默认数据量和空数据量。
2. 浅色稳定态和深色稳定态。
3. 安装/更新/卸载/授权弹窗与 toast。
4. 菜单、hover、disabled、focus、loading、滚底、分页。
5. 900×680 设置窗口之外的独立页面尺寸。
## 补采检查表
主协调下一次统一补采应至少保存:
- 设置 target id、窗口 URL 和 viewport。
- `[data-settings-tab="buddyApps"]` 点击前后稳定帧。
- 主页面 `.settings-modal__panel` 的 DOM、layout、可见文本和截图。
- `BuddyAppsPanel-vC0qX_Oo.js`/新 hash 的完整 REA script source。
- `BuddyAppsPanel-OzkcFEe0.css`/新 hash 的完整 REA style source。
- 默认列表数量及至少一个已安装、一个未安装、一个有更新条目的字段。
- 主操作的 DOM selector、文案、disabled 条件和确认弹窗。
- 浅色与深色稳定态;若窗口主题由设置控制,记录切换证据。
- 只读网络/状态来源证据;不在主页面直接执行真实安装或卸载。
建议的探针起点:
```json
[
{
"kind": "click",
"selector": "[data-settings-tab=\"buddyApps\"]",
"frames": 0
},
{
"kind": "wait",
"duration_ms": 750,
"frames": 1
}
]
```
探针完成后以 `.settings-navigation__item--active[data-settings-tab="buddyApps"]` 确认路由,再检查 `.settings-modal__panel` 内是否出现新模块内容。
## 决策
1. **不把发现浮层等同于安装中心。** 两者共享可能的数据,但当前证据将它们拆为 switcher 与 manager 两个 surface。
2. **不在主页面证据缺失时实现安装按钮。** 后续先建立 registry/operation 状态,再接真实能力。
3. **把 installed、active、authorized、dependency-ready 分开。** 现有原版已证明选择/授权/依赖是独立步骤。
4. **应用 ID 使用 `applicationId` 作为首选去重键。** `templateId`、version 和 schema 另存。
5. **远端目录失败不等于空目录。** 本地已安装 registry 必须离线可见,远端错误必须可恢复。
6. **保留用户移除设置入口的决定。** 安装中心的最终入口位置需要主协调明确,不能擅自恢复 `buddyApps` 设置项。
7. **sample app 名称只作截图样例。** 通达信等运行时条目不得写死。
## 本轮核对命令
本轮没有运行测试或构建。除下方明确列出的 REA target 枚举和两次声明式探针外,其余核对均为静态读取。
```text
rg --files docs | rg '安装|应用|发现|中心|模块拆解'
Get-ChildItem .tmp -Recurse | Where-Object FullName -match 'rea-todo18'
rg -n '安装中心|发现应用|Discover|app discover|install' docs src scripts
Get-Content docs/复刻待办清单-2026-10-17.md
Get-Content src/renderer/src/components/AppDiscoverPopover.tsx
Get-Content src/renderer/src/components/app-discover-popover.css
Get-Content src/renderer/src/capabilities/CapabilityCenter.tsx
Get-Content scripts/verify-app-discover.cjs
Get-Content .tmp/rea-todo18-BuddyAppDiscoverPanel.js
Get-Content .tmp/rea-todo18-BuddyAppIcon.js
Python 解析 .tmp/rea-todo18-*.json 的 evidence_id、target、captured_at、viewport、artifact SHA-256、limitations
Python 解析 .tmp/rea-todo18-main-scripts.json 的 contexts-DgzzFjnf.js source artifact
Python 解析 .tmp/rea-todo18-styles-current.json 的 contexts-BkjwYSZT.css source artifact
Python 解析 .tmp/rea-todo18-discover-state/layout.json 的浮层几何
Python 解析 .tmp/rea-todo18-settings/layout.json 的设置导航结构
Python 在保存的 contexts-DgzzFjnf.js 中检索 API、selection、consent、dependency、settings route
```
2026-10-17 新增的 REA 读取与失败记录:
```text
node .tmp/rea-css-runtime/scripts/rea.mjs list-electron-targets http://127.0.0.1:9223
REA inspect-electron-page:主窗口 + 仅 wait 的 visual_probe
REA inspect-electron-page:主窗口 + 打开账户菜单/设置窗口的 visual_probe
结果:target list 成功;无操作探针成功;设置打开探针 invalid_request,未生成 Evidence ID
保存:.tmp/rea-four-modules-install-targets.json
.tmp/rea-four-modules-install-probe-minimal.json
.tmp/rea-four-modules-install-open-settings.json
.tmp/rea-four-modules-install-open-settings-retry.json
```
## 风险
1. **把浮层当完整安装中心**:会严重高估完成度。
2. **把 MCP 依赖安装冒充应用安装**:原版代码明确区分 dependency 与 application 选择。
3. **恢复已移除设置入口而不确认**:与用户此前要求冲突。
4. **远端服务不可用时伪造状态**:可产生虚假 installed/update 结果。
5. **账号/企业隔离错误**:可能把企业目录、授权或用量混进个人数据。
6. **授权并发和账号切换**:可能出现旧 consent 写入新账号。
7. **安装/更新破坏用户内容**:需要原子操作、备份、回滚和明确确认。
8. **敏感信息泄漏**:authorization code、token、secret 和完整远端 URL 不应进入日志/普通本地状态。
9. **运行时动态条目被写死**:sample app 名称、顺序和描述会随账号/服务变化。
10. **主页面像素误判**:当前没有该页面任何 REA 视觉,不能从浮层几何推导。
## 交接结论
本轮安装中心专项到此收口:已有足够证据拆出“发现浮层”和“安装中心主页面”两个 surface,以及目录、选择、授权、依赖和未知安装生命周期边界;但安装中心主页面仍没有 REA 运行时证据。下一步需要先获得可操作的原版设置窗口 target,再点击 `[data-settings-tab="buddyApps"]` 并同次采集 DOM、视觉、脚本和样式。补采成功后,优先恢复 `BuddyAppsPanel` 的 DOM/CSS 和页面状态,再决定 manager 的真实信息架构。YCode 已有浮层壳可以保留,但其数据层仍是本地能力适配,必须和后续云应用 registry 解耦。