# 启动页预热方案（适配当前代码）

## 背景

当前代码已经把一部分冷启动前移到了主进程，但聊天页仍然会在服务未 ready 时提前打开，并通过发送区禁发来暴露启动过程。用户感知上会变成“聊天窗口已经打开，但发送按钮是灰的，还要等待准备环境”。

这次方案的目标是把初始化完整收拢到启动页，聊天页只在 `chatReady === true` 后进入；同时对云配置增加“缓存优先 + 后台增量同步”，缩短二次启动时间。

## 当前代码问题定位

- 主进程已经有预热链路：`apps/desktop/src/main/index.ts`
  - 启动时会拉取员工配置、启动 bundled runtime、连接 gateway。
- 状态聚合已经存在：`apps/desktop/src/main/ipc.ts`
  - `WorkspaceSummary` 已包含 `chatReady`、`chatLaunchState`、`startupPhase`、`startupMessage`。
- 问题主要出在渲染层：`apps/ui/src/App.tsx`
  - 聊天页在未 ready 时提前进入。
  - 发送按钮和提示文案绑定到运行时 ready 状态，导致界面像“卡住”。

## 本次适配

### 1. 主进程预热保留，但改成缓存优先

- 在 `OpenClawConfigClient` 中加入运行时云配置缓存。
- 缓存内容包含：
  - 上次成功的员工配置 payload
  - 配置摘要
  - 当前员工密钥指纹
- 启动时优先尝试读取缓存：
  - 如果缓存命中且密钥未变，bundled runtime 直接基于缓存配置启动。
  - 启动完成后再后台执行一次云端刷新。
- 如果缓存不存在或密钥变更：
  - 仍按原始链路阻塞拉取 `fetchConfig("init")`。

### 2. 缓存失效策略

- 当用户更换或清空员工密钥时，立即清理旧缓存。
- 缓存只在密钥指纹一致时复用，避免把上一位员工的配置拿来启动。

### 3. 启动页成为聊天入口

- 聊天视图新增启动页门禁：
  - 服务未 ready 时，只展示启动页，不渲染聊天消息区和发送区。
  - 服务 ready 后，自动进入聊天页。
- 启动页展示：
  - 主状态文案
  - 进度条
  - 四段步骤：读取本地配置、准备本地助手、连接聊天服务、进入对话
  - 失败时保留“重新准备”和“打开设置”入口

### 4. 聊天页恢复正常可发状态

- 聊天页不再把发送按钮绑定到启动期状态。
- 进入聊天页后：
  - 发送按钮只受“已绑定、输入非空、未发送中、未保存中”控制。
- `ensureChatAvailable()` 保留，但只用于异常恢复：
  - 理论上不再承担首开冷启动主路径。

### 5. 现有优化继续保留

- 只展示 `user` / `assistant` 主消息。
- 保留可折叠“思考过程”面板。
- 保留 `completed` 无 `delta` 的兜底显示逻辑。

## 涉及文件

- `apps/desktop/src/main/index.ts`
- `apps/desktop/src/main/ipc.ts`
- `apps/desktop/src/main/services/cloud-api.ts`
- `apps/desktop/src/main/services/app-config.ts`
- `apps/ui/src/App.tsx`
- `apps/ui/src/styles.css`

## 验收标准

- 已绑定情况下，打开应用先看到启动页，而不是灰按钮聊天页。
- 二次启动且缓存可用时，启动页等待明显短于首次启动。
- 启动完成后进入聊天页，发送按钮默认可用。
- 更换员工密钥后，不复用旧员工缓存。
- runtime 或 gateway 异常掉线时，仍能通过恢复逻辑重新可用。

## 测试建议

1. 首次启动，无缓存
   - 应显示启动页并完成完整预热。
2. 再次启动，有缓存
   - 应明显更快进入聊天页。
3. 更换员工密钥
   - 旧缓存应失效，不应沿用旧员工配置。
4. 断网启动
   - 有缓存时可继续进入；无缓存时停留在启动失败页。
5. 聊天页回归
   - 进入聊天页后首条消息不应再承担完整冷启动链路。
