initialize Electron desktop app and remove unused files
Build / build (push) Canceled after 0s
Playwright / browser (push) Canceled after 0s

This commit is contained in:
2026-10-25 01:09:01 +08:00
commit 01d9e301fc
877 changed files with 262513 additions and 0 deletions
+259
View File
@@ -0,0 +1,259 @@
# Phase 006 — Arco 迁移:聊天页
| 项 | 值 |
|---|---|
| 目标 | 聊天页全量换 Arco,功能与旧版完全对等 |
| 前置 | Phase 005 通过(`docs/ui-baseline.md` 已定稿) |
| 产出 | 聊天全流程手工验收清单全绿 |
| 参考 | `docs/03-施工蓝图.md` §8.1 |
---
## 0. 为什么聊天页优先
它是全站唯一的 Socket.IO 流式实时页,含审批弹窗、工具轨迹、思考块、Markdown 渲染、虚拟滚动、附件上传。**最难的坑在这里踩完,后面 20 个 CRUD 页就是纯体力活。**
---
## 1. 硬性能规则:消息气泡内禁用 Arco 组件
流式增量渲染时,`MessageItem.vue` 每次 token 到达都 re-render。Arco 组件被包进消息气泡会引入不必要的 diff 开销。
```
✅ 允许:a-button(输入区工具条、审批按钮)
✅ 允许:a-modal(审批弹窗,在气泡外层)
❌ 禁止:a-tag / a-avatar / a-progress 等包在气泡内的装饰性组件
❌ 禁止:气泡内任何有内部状态的组件
```
气泡内用原生 HTML + 项目自己的 SCSS。这条已写进 `docs/ui-baseline.md`。
---
## 2. 改动落点清单
```
packages/client/src/views/hermes/ChatView.vue
packages/client/src/components/hermes/chat/ChatPanel.vue
packages/client/src/components/hermes/chat/ChatInput.vue
packages/client/src/components/hermes/chat/MessageList.vue
packages/client/src/components/hermes/chat/MessageItem.vue
packages/client/src/components/hermes/chat/VirtualMessageList.vue
packages/client/src/components/hermes/chat/SessionSearchModal.vue
packages/client/src/components/hermes/chat/HistoryMessageList.vue
packages/client/src/components/hermes/chat/FilesPanel.vue
packages/client/src/components/hermes/chat/DrawerPanel.vue
packages/client/src/components/hermes/chat/MarkdownRenderer.vue
packages/client/src/components/hermes/chat/OutlinePanel.vue
packages/client/src/components/hermes/chat/TerminalPanel.vue
packages/client/src/components/hermes/chat/ConversationMonitorPane.vue
packages/client/src/stores/hermes/chat.ts
packages/client/src/stores/hermes/files.ts
packages/client/src/api/hermes/chat.ts
```
---
## 3. 功能任务 1 — 布局与容器
| 原组件 | 新组件 | 备注 |
|---|---|---|
| `NLayout` / `NLayoutSider` | `a-layout` / `a-layout-sider` | 三栏:会话列表 / 聊天区 / 侧面板 |
| `NCard` | `a-card` | 会话项卡片 |
| `NScrollbar` | `a-scrollbar` | **注意**:虚拟滚动与 `a-scrollbar` 冲突,见 §5 |
| `NEmpty` | `a-empty` | 空态 |
| `NPopover` | `a-popover` | 会话项操作菜单 |
| `NTooltip` | `a-tooltip` | |
| `NDrawer` | `a-drawer` | 侧面板 |
| `NCollapse` | `a-collapse` | 工具轨迹折叠 |
---
## 4. 功能任务 2 — 输入区
| 原组件 | 新组件 |
|---|---|
| `NInput` | `a-textarea` |
| `NButton` | `a-button` |
| `NSelect`(模型) | `a-select` |
| `NDropdown` | `a-dropdown` |
| `NPopconfirm` | `a-popconfirm` |
| `NProgress`(录音) | `a-progress` |
| `NIcon` | Arco Icon |
`ChatInput.vue` 里有 `useKeyboard` / 高度自适应(`chat-input-height.test.ts` 覆盖),**不要重构这块逻辑**,只换渲染层。
---
## 5. 功能任务 3 — 消息列表(**最高风险区**)
### 5.1 虚拟滚动
`VirtualMessageList.vue` 用 `vue-virtual-scroller`。
**`a-scrollbar` 与 `vue-virtual-scroller` 不能同时管滚动容器**。二选一:
- 保留 `vue-virtual-scroller` 的滚动容器,去掉 `a-scrollbar` 包裹
- 或放弃虚拟滚动改 `a-table-virtual`(不推荐,会破坏消息气泡的自适应高度)
**结论**:保留 `vue-virtual-scroller`,去掉 `a-scrollbar`。在 `docs/arco-mapping.md` 记下这条例外。
### 5.2 流式渲染
`MessageItem.vue` 的 re-render 频率高。确保:
- 气泡内无 Arco 组件(§1)
- token 拼接走局部 ref,不触发整列表 diff
- Markdown 渲染有防抖(保留旧版逻辑)
### 5.3 审批与澄清弹窗
**时序敏感**:必须打断流式。这是 `a-modal` 与流式状态的竞争点。
- 审批请求到达 → 流式暂停 → 弹窗
- 用户选择 → 恢复流式
- 断线重连时若有未处理的审批,要能恢复
`MessageItem.vue` 里的审批 UI 改成 `a-modal` 或内联 `a-card` + `a-button`(内联更好:不打断视觉连续性)。**内联是首选。**
### 5.4 工具轨迹
`a-collapse` + `a-timeline`。折叠状态要记住(重渲染不丢)。
### 5.5 Markdown / 代码 / 图表
`MarkdownRenderer.vue` 保持不变(不涉及 naive)。相关测试:
```
markdown-rendering.test.ts
markdown-rendering-mermaid-import-timeout.test.ts
markdown-special-mentions.test.ts
highlight-safety.test.ts
highlight-helper.test.ts
```
这些**不改**,跑绿即可。
---
## 6. 功能任务 4 — 会话列表
`SessionListItem.vue` / `SessionSearchModal.vue`:
| 原组件 | 新组件 |
|---|---|
| `NCard` | `a-card` |
| `NInput`(搜索) | `a-input` |
| `NEmpty` | `a-empty` |
| `NTag`(标签) | `a-tag` |
| `NDropdown` | `a-dropdown` |
| `NBadge` | `a-badge` |
| `NPopconfirm`(删除确认) | `a-popconfirm` |
---
## 7. 功能任务 5 — 全局 hook 替换
全量 grep 替换,只用 Phase 005 §5 建的适配层:
```bash
cd packages/client/src
grep -rln "useMessage\|useDialog\|useNotification" components/hermes/chat/ stores/hermes/chat.ts
```
改成:
```ts
// 旧
const message = useMessage() // naive hook
// 新
import { useMessage } from '@/composables/useMessage'
const message = useMessage() // 我们的 composable,签名一致
```
**签名一致,所以正文代码几乎不用改**,只改 import 来源。这是 Phase 005 §5 的设计目的。
---
## 8. 功能任务 6 — 补测试
新建 `tests/client/message-item-arko.test.ts`:
- 消息气泡内不含 Arco 组件标签(防止 §1 规则被破坏)
- 审批弹窗状态机正确
- 流式追加消息后 DOM 结构不抖动
---
## 9. 验收(**手工逐条走,不许跳**)
### 9.1 命令
```bash
cd /Users/jack/source/MyProject/js/hermes-ui
grep -cE "from ['\"]naive-ui['\"]" packages/client/src/components/hermes/chat/*.vue \
packages/client/src/views/hermes/ChatView.vue \
packages/client/src/stores/hermes/chat.ts
# 期望:全部 0
npm run build
npm run test
npm run test:e2e
```
### 9.2 手工清单
**流式与渲染**
- [ ] 发消息 → 流式逐字输出 → 完成态
- [ ] 工具调用轨迹展开 / 收起
- [ ] 思考块(thinking)正常显示 / 隐藏
- [ ] 长消息滚动流畅(虚拟滚动没坏)
- [ ] 滚动到底部自动跟随
**交互**
- [ ] 审批请求弹出 → 选择 → 流式继续
- [ ] 澄清请求 → 回答 → 继续
- [ ] 中断(stop)按钮生效
- [ ] 重新生成 / 分支切换
- [ ] 会话切换时状态正确重置
**内容**
- [ ] Markdown 标题 / 列表 / 表格
- [ ] 代码块高亮 + 复制按钮
- [ ] KaTeX 公式
- [ ] Mermaid 图(注意导入超时)
- [ ] @提及高亮
**多标签与断线**
- [ ] 两个标签页开同一会话(`chat-session-multitab.spec.ts`)
- [ ] 断网 → 重连 → 流式恢复(`chat-run-reconnect.test.ts`)
- [ ] 移动端窄屏布局(`chat-message-mobile-layout.test.ts`)
**其他**
- [ ] 附件上传 + 引用
- [ ] 文件面板(FilesPanel)正常
- [ ] 大纲面板(OutlinePanel)正常
- [ ] 终端面板(TerminalPanel)正常
- [ ] 会话搜索正常
- [ ] 明暗双主题各过一遍
---
## 10. 风险
| # | 风险 | 缓解 |
|---|---|---|
| P6-1 | `a-scrollbar` 与虚拟滚动打架 → 白屏或列表不动 | §5.1 已定方案,去掉 `a-scrollbar` |
| P6-2 | 流式性能退化(气泡内 Arco 组件) | §1 硬规则 + `message-item-arko.test.ts` 卡住 |
| P6-3 | 审批弹窗与流式状态竞争 → 卡死 | §5.3 优先内联方案,减少 modal 竞争 |
| P6-4 | `useMessage` 等 hook 改 import 时漏改某个文件 | §7 的 grep 逐个确认,编译会兜底 |
| P6-5 | 顺手重构了 chat store 逻辑 | 硬规则:只换渲染层,不动逻辑。逻辑改动属 Phase 007+ |
| P6-6 | 测试大量 fail 干扰判断 | 先确认 `npm run test` 的 fail 是否本来就存在(Phase 004 基线),只处理新增 |
---
## 11. 完成标志
进入 Phase 007(其余 20 视图批量迁移)。