716 lines
38 KiB
Markdown
716 lines
38 KiB
Markdown
# hermes-ui 施工蓝图
|
||
|
||
> 基线:`hermes-web-ui` 0.6.29(只读参考 `/Users/jack/source/OtherProjectTemp/ekko-studio`)
|
||
> 目标仓库:`/Users/jack/source/MyProject/js/hermes-ui`
|
||
> 本文所有"现状"结论均来自源码核实,行号为 0.6.29 快照。
|
||
|
||
---
|
||
|
||
## 0. 已确认决策
|
||
|
||
| 项 | 结论 |
|
||
|---|---|
|
||
| 包名 / 产品名 | `hermes-ui` |
|
||
| 前端 | Vue 3 + `<script setup lang="ts">` + Vite + Pinia + Vue Router(hash),全部沿用 |
|
||
| 后端 | Koa 2 + TS + Socket.IO + better-sqlite3,全部沿用 |
|
||
| 实时通信 | Socket.IO `/chat-run` 命名空间协议不变 |
|
||
| UI 组件库 | **Naive UI 全量换 Arco Design Vue**,不双库共存 |
|
||
| 特效层 | **ArkScope** vendor 进项目,只做装饰性位面 |
|
||
| 桌面端 | 砍掉 `packages/desktop` 整包 |
|
||
| 官网 | 砍掉 `packages/website` |
|
||
| 内置 skills | **保留** `packages/skills` |
|
||
| IM 频道 | 保留(K 组多平台 + gateway 守护) |
|
||
| i18n | 只保留 `zh` + `en` |
|
||
| 品牌 | 不得出现 `ekko` / `hermes-web-ui` 字样;`Hermes` 保留 |
|
||
| 配置层标识 | **保留** `HERMES_WEB_UI_*` 前缀与 `~/.hermes-web-ui` 数据目录 |
|
||
| 依赖 | lockfile 不升级(版本不升,只做增删) |
|
||
| 砍除功能组 | I 组(Claude Code / Codex 编程代理)、J 组(ekko-agent)、P 组(Petdex)、Electron |
|
||
|
||
---
|
||
|
||
## 1. 源码核实结论(与 01/02 文档有出入的地方)
|
||
|
||
以下 6 条与文档不一致,**以本节为准**。
|
||
|
||
### 1.1 这不是 npm workspaces
|
||
|
||
根 [package.json](file:///Users/jack/source/OtherProjectTemp/ekko-studio/package.json) **没有 `workspaces` 字段**。`packages/client` 与 `packages/server` 都不含自己的 `package.json`,它们的依赖统一写在根 `package.json` 里。只有 `packages/desktop` 与 `packages/ekko-agent` 各自有 `package.json` + `package-lock.json`。
|
||
|
||
**影响**:01 文档"删除根 workspace 引用"这条不存在。实际要动的是根 `package.json` 的 `scripts`、`bin`、`dependencies`。
|
||
|
||
### 1.2 gateway 自启不需要迁移
|
||
|
||
01 文档称"gateway 自启原逻辑有一半长在 Electron 生命周期里,需迁到 Koa 启动钩子"。**实际不需要迁**:
|
||
|
||
- [index.ts](file:///Users/jack/source/OtherProjectTemp/ekko-studio/packages/server/src/index.ts#L176-L222) 的 `startRuntimeServicesBeforeListen()` / `startRuntimeServicesAfterListen()` 里已经调用了 `ensureProfileGatewaysRunning()`。
|
||
- Electron 侧只有 [gateway-autostart.ts](file:///Users/jack/source/OtherProjectTemp/ekko-studio/packages/server/src/services/hermes/gateway-autostart.ts#L156-L163) 的 `shouldRecoverWindowsDesktopGatewayOrphans()` 依赖 `HERMES_DESKTOP`,以及一个注册在 `/api/desktop/shutdown` 的关闭回调([index.ts](file:///Users/jack/source/OtherProjectTemp/ekko-studio/packages/server/src/index.ts#L122-L160))。
|
||
|
||
**结论**:自启逻辑零迁移成本。只需删掉 `HERMES_DESKTOP` 分支。
|
||
|
||
### 1.3 文档漏了两个包
|
||
|
||
| 包 | 内容 | 处置 |
|
||
|---|---|---|
|
||
| `packages/website` | 独立 vite 配置 + `tsconfig.website.json` + `website-deploy.yml` workflow + `public/docs/` 静态文档站 | **砍掉** |
|
||
| `packages/skills` | 5 个内置 skill,被 [skill-injector.ts](file:///Users/jack/source/OtherProjectTemp/ekko-studio/packages/server/src/services/hermes/skill-injector.ts#L55-L58) 注入给 hermes 的 `skills/` 目录 | **保留** |
|
||
|
||
两者都不在 02 文档的 A~Q 分组里。
|
||
|
||
### 1.4 I/J 组可安全砍除
|
||
|
||
[run-chat/index.ts](file:///Users/jack/source/OtherProjectTemp/ekko-studio/packages/server/src/services/hermes/run-chat/index.ts#L467-L496) 的 dispatch 结构:
|
||
|
||
```
|
||
ensureBridgeReadyForChatRun() → handleBridgeRun() → return // 主路径,先执行
|
||
if (isEkkoAgentExecution(data)) → handleEkkoAgentRun() → return // J 组
|
||
→ handleCodingAgentRun() // I 组兜底
|
||
```
|
||
|
||
- bridge 分支在最前且有 `return`,砍掉后两条分支不影响它。
|
||
- 全局 Agent 走 [global-agent/server.ts](file:///Users/jack/source/OtherProjectTemp/ekko-studio/packages/server/src/services/global-agent/server.ts#L10) → `getChatRunServer().runAndWait()`,砍 I/J 后自动只走桥。
|
||
- 群聊走 [group-chat/agent-clients.ts](file:///Users/jack/source/OtherProjectTemp/ekko-studio/packages/server/src/services/hermes/group-chat/agent-clients.ts) 的 `AgentBridgeClient` 直连,与 I/J 无关。
|
||
|
||
**唯一要动的是 `isCodingAgentExecution` 的返回值语义**(见 §5.4),它同时被 [L289](file:///Users/jack/source/OtherProjectTemp/ekko-studio/packages/server/src/services/hermes/run-chat/index.ts#L289) / [L423](file:///Users/jack/source/OtherProjectTemp/ekko-studio/packages/server/src/services/hermes/run-chat/index.ts#L423) / [L707](file:///Users/jack/source/OtherProjectTemp/ekko-studio/packages/server/src/services/hermes/run-chat/index.ts#L707) 用于 `state.isWorking` 判定。
|
||
|
||
### 1.5 Naive UI 渗透面是 100 个文件
|
||
|
||
02 文档说"27 个视图"。实际 `from 'naive-ui'` 共 105 处,分布在 **100 个文件**,包含 `components/`、`stores/`、`composables/` 下的深层文件,不只是视图层。**必须先建映射表,不能盲改。**
|
||
|
||
### 1.6 ArkScope 的真实形态
|
||
|
||
`triplepiers/ArkScope`("对鹰角 UI 组件的拙劣复现",Vue 3 + Vite,**无 LICENSE**,仓库 322MB):
|
||
|
||
```
|
||
src/components/
|
||
ScrambleTitle/ 文字解码动画(塞壬唱片)—— 最轻,纯装饰 ✅
|
||
IsometricWave/ 类亚克力 hover 交互 —— 中等 ✅
|
||
Particle2D/ Particle3D/ 点云斥力/旋转效果 —— 重,含 3D 模型 ❌ 风险高
|
||
EndfieldSidebar/ 悬停展开侧边栏 —— 与 AppSidebar 冲突 ❌
|
||
OperatorCarousel/ 干员轮播 —— 强依赖游戏素材,脱离素材无意义 ❌
|
||
ArknightsMedia/ GameplayAlbum/ NoticeCarousel/ FullScreenNavigator/ NewsList/
|
||
Endfield/*/ EndfieldSidebar/ 全部强绑定游戏素材 ❌
|
||
```
|
||
|
||
**结论**:只有 `ScrambleTitle` 和 `IsometricWave` 是真正可脱离素材复用的装饰位面。其余组件的价值在于**视觉手法**(斜切遮罩、噪点、扫描线、Reveal & Blink),需要抽取手法而非搬运代码。
|
||
|
||
`public/assets/` 下 131 个路径全是鹰角游戏美术资源(角色立绘、Banner、字体)—— **不进项目**。
|
||
|
||
---
|
||
|
||
## 2. 仓库骨架(Phase 0)
|
||
|
||
### 2.1 目标结构
|
||
|
||
```
|
||
hermes-ui/
|
||
├── package.json # name: "hermes-ui",依赖表裁剪后重写
|
||
├── package-lock.json # 保留旧版,Phase 2 一次性重生成
|
||
├── vite.config.ts # root: packages/client,删除 naive-ui chunk
|
||
├── vitest.config.ts
|
||
├── playwright.config.ts
|
||
├── tsconfig.json / .app.json / .node.json
|
||
├── nodemon.json # watch 去掉 packages/ekko-agent/src
|
||
├── Dockerfile / docker-compose.yml / .dockerignore
|
||
├── AGENTS.md # 重写(继承硬规则,替换 package 地图)
|
||
├── ARCHITECTURE.md
|
||
├── DEVELOPMENT.md
|
||
├── docs/
|
||
│ ├── harness/{README,validation,worktree-runbook,pr-review}.md
|
||
│ └── chat-chain-changes/ # 桥接链路变更片段(见 §8.2)
|
||
├── packages/
|
||
│ ├── client/{public,src,index.html}
|
||
│ ├── server/src
|
||
│ └── skills/ # 保留
|
||
├── scripts/
|
||
│ ├── build-server.mjs
|
||
│ ├── generate-openapi.mjs
|
||
│ └── harness-check.mjs # 重写(见 §8.3)
|
||
└── tests/{client,server,e2e,shared}
|
||
```
|
||
|
||
### 2.2 拷贝来源与排除清单
|
||
|
||
从旧版拷 `packages/client`、`packages/server`、`packages/skills`、`tests`、`scripts`、`bin`、根配置文件。
|
||
|
||
**明确不拷**:
|
||
- `packages/desktop`(整包)
|
||
- `packages/website`(整包)
|
||
- `packages/ekko-agent`(整包)
|
||
- `docs/`(旧文档,含大量旧品牌;只拷 `docs/harness/` 与 `docs/chat-chain-changes/README.md`)
|
||
- `packages/esp32-c3`(O 组之外的固件,本项目不做硬件;**若你后续要做 ESP32 语音硬件再单独拷**)
|
||
- `public/coding-agents/ekko-agent.png`
|
||
|
||
### 2.3 Phase 0 验收
|
||
|
||
```bash
|
||
cd /Users/jack/source/MyProject/js/hermes-ui
|
||
npm ci --ignore-scripts # 用旧 lockfile 先装通
|
||
npm run build # 必须过(此时仍含 desktop 相关脚本残留)
|
||
```
|
||
|
||
风险:`package.json` 的 `prepare` 脚本会触发 build(`"[ -d dist ] || npm run build"`),`npm ci` 时可能自动跑 build。**Phase 0 先把 `prepare` 摘掉,Phase 6 再恢复。**
|
||
|
||
---
|
||
|
||
## 3. 阶段划分总览
|
||
|
||
| Phase | 名称 | 依赖 | 可独立验收的标志 |
|
||
|---|---|---|---|
|
||
| 0 | 仓库骨架搭建 | — | `npm ci && npm run build` 通过 |
|
||
| 1 | 去品牌 | 0 | 全仓 grep 无 `ekko` / `hermes-web-ui` |
|
||
| 2 | 砍 I/J 组 | 0 | 聊天仍走桥,编程代理全消失 |
|
||
| 3 | 砍桌面端 + 官网 | 0 | 无 Electron 依赖,网关自启仍工作 |
|
||
| 4 | ArkScope vendor + 样板页 | 1,3 | 登录页有装饰位面,风格基线定稿 |
|
||
| 5 | Arco 迁移:聊天页 | 4 | 聊天全流程功能对等 |
|
||
| 6 | Arco 迁移:批量 | 5 | 无 `naive-ui` 残留 |
|
||
| 7 | 测试与 CI 收口 | 2-6 | 全绿 |
|
||
|
||
**Phase 4 必须早于 Phase 5/6**:先定风格基线,再批量迁移,否则 100 个文件会被改两遍。
|
||
|
||
---
|
||
|
||
## 4. Phase 1 — 去品牌
|
||
|
||
### 4.1 判定标准
|
||
|
||
最终 `grep -ri "ekko\|hermes-web-ui"` 在以下范围内**必须零命中**(`packages/`、`tests/`、`scripts/`、`bin/`、根配置、`.github/`):
|
||
|
||
**例外白名单**(允许保留旧标识):
|
||
- `HERMES_WEB_UI_*` / `HERMES_WEBUI_STATE_DIR` 环境变量名
|
||
- `~/.hermes-web-ui` 默认数据目录名
|
||
- localStorage key:`hermes_brightness` / `hermes_style` / `hermes_locale`
|
||
|
||
> 这些是你主动决定保留的。改名会破坏已有部署脚本与数据目录。
|
||
|
||
### 4.2 改动落点清单
|
||
|
||
#### A. 根配置
|
||
|
||
| 文件 | 改动 |
|
||
|---|---|
|
||
| `package.json` | `name` → `hermes-ui`;`repository` / `homepage` 指向你自己的仓库或直接删;`keywords` 去 `hermes-web`;`bin` 改名 `hermes-ui` / `hermes-ui-mcp` |
|
||
| `README.md` / `README_zh.md` | 重写 |
|
||
| `AGENTS.md` | 重写 package 地图(删 desktop / website / ekko-agent 条目) |
|
||
| `ARCHITECTURE.md` | 删 "Electron desktop distribution" 段落与 Desktop Release Flow 整节 |
|
||
| `DEVELOPMENT.md` | L47 "Match existing Naive UI patterns and avoid adding a new UI library" → Arco 表述 |
|
||
| `Dockerfile` / `docker-compose.yml` | 镜像名去旧品牌 |
|
||
| `.dockerignore` / `.gitignore` | 检查旧品牌路径 |
|
||
|
||
#### B. `packages/server/src`
|
||
|
||
| 文件 | 改动 |
|
||
|---|---|
|
||
| `controllers/update.ts` | **重点**。L12-13 预览目录名 `hermes-web-ui-pereview`、L365 `hermes-web-ui/bin/hermes-web-ui.mjs`、L728 `pkg?.name !== 'hermes-web-ui'`、L935/L1156 `User-Agent`、L1034/L1046 npm 全局安装 `hermes-web-ui@latest`、L1065/1076/1092 提示文案。**全部改为 `hermes-ui`** |
|
||
| `config.ts` | L65 `https://hermes-studio.ai` 相关的默认下载地址;保留所有 `HERMES_WEB_UI_*` |
|
||
| `services/hermes/agent-bridge/manager.ts` | L16 OpenRouter attribution URL(`hermes-studio.ai` → 你的地址或删) |
|
||
| `lib/llm-prompt.ts` | 3 处 `/Users/ekko/Desktop` 是原作者本机路径,**直接删除该分支逻辑** |
|
||
| `services/hermes/studio-mcp-autoinject.ts` | 文件名含 `studio`;检查内容是否含旧品牌串 |
|
||
|
||
#### C. `packages/client`
|
||
|
||
| 文件 | 改动 |
|
||
|---|---|
|
||
| `index.html` | L11 `apple-mobile-web-app-title`、L13 `<title>Hermes Studio</title>` → `hermes-ui` |
|
||
| `public/manifest.webmanifest` | `name` / `short_name` |
|
||
| `i18n/locales/{zh,en}.ts` | 所有旧品牌文案(约 5 处/语言,见下) |
|
||
| `data/changelog.ts` | 旧版本更新日志里的品牌串。**建议整体清空**,从 0.6.29 重新起 |
|
||
| `public/coding-agents/ekko-agent.png` | 删除(Phase 2 一并处理) |
|
||
| `components/hermes/chat/MessageList.vue` 等 | grep 命中的显示文案 |
|
||
|
||
#### D. `tests/`
|
||
|
||
`tests/client/pwa-metadata.test.ts` 断言 title/manifest,需同步改。
|
||
`tests/ekko-agent/` 整目录 Phase 2 删除。
|
||
|
||
### 4.3 i18n 收敛到 zh + en
|
||
|
||
- 删除 `locales/{zh-TW,ja,ko,fr,es,de,pt,ru}.ts`
|
||
- [messages.ts](file:///Users/jack/source/OtherProjectTemp/ekko-studio/packages/client/src/i18n/messages.ts) 的 `supportedLocales` 改为 `['en', 'zh']`
|
||
- [i18n/index.ts](file:///Users/jack/source/OtherProjectTemp/ekko-studio/packages/client/src/i18n/index.ts#L7-L34) 的 `normalize()` 简化为 zh 判断 + 默认 en
|
||
- [i18n-coverage.test.ts](file:///Users/jack/source/OtherProjectTemp/ekko-studio/tests/client/i18n-coverage.test.ts#L23-L34) 的 `rawMessages` 改为两项
|
||
|
||
**硬规则保留**:新增用户可见字符串必须同时写 `zh.ts` 与 `en.ts`。i18n-coverage 测试是这个规则的机械保障,不要删。
|
||
|
||
### 4.4 Phase 1 验收
|
||
|
||
```bash
|
||
grep -ri "ekko" packages/ tests/ scripts/ bin/ .github/ *.json *.md Dockerfile* # 零命中
|
||
grep -ri "hermes-web-ui" packages/ tests/ scripts/ bin/ .github/ # 零命中
|
||
npm run test && npm run build
|
||
```
|
||
|
||
风险:`update.ts` 的 npm 全局安装路径改名后,**如果你不发布 npm 包,在线更新功能实际不可用**。建议 Phase 1 先把"检查更新"入口的文案改成"当前为源码运行",在线更新逻辑保留但标注不可用;等你决定发布方式再接。
|
||
|
||
---
|
||
|
||
## 5. Phase 2 — 砍 I 组 / J 组
|
||
|
||
### 5.1 删除文件
|
||
|
||
**I 组(编程代理)**
|
||
```
|
||
packages/client/src/views/hermes/CodingAgentsView.vue
|
||
packages/client/src/api/coding-agents.ts
|
||
packages/server/src/routes/coding-agents.ts
|
||
packages/server/src/routes/claude-code-proxy.ts
|
||
packages/server/src/routes/codex-proxy.ts
|
||
packages/server/src/controllers/coding-agents.ts
|
||
packages/server/src/services/coding-agents.ts
|
||
packages/server/src/services/agent-runner/ # 整个目录(含 stream-tee 网关)
|
||
packages/client/public/coding-agents/ # 整个目录
|
||
```
|
||
|
||
**J 组(ekko-agent)**
|
||
```
|
||
packages/server/src/services/ekko-agent/ # manager.ts + mcp.ts
|
||
packages/server/src/services/hermes/run-chat/handle-ekko-agent-run.ts
|
||
packages/ekko-agent/ # 整个包
|
||
tests/ekko-agent/ # 整个目录
|
||
```
|
||
|
||
**相关测试**
|
||
```
|
||
tests/server/coding-agents-*.test.ts (4 个)
|
||
tests/server/coding-agent-run-manager-windows.test.ts
|
||
tests/server/agent-runner-gateway.test.ts
|
||
tests/server/handle-coding-agent-run.test.ts
|
||
tests/client/coding-agent-api-modes.test.ts
|
||
```
|
||
|
||
### 5.2 路由与导航清理
|
||
|
||
| 文件 | 改动 |
|
||
|---|---|
|
||
| `routes/index.ts` | 删 L11 `codingAgentRoutes`、L13 `claudeCodeProxyRoutes`、L14 `codexProxyRoutes` 的 import 与 L64/65/79 的 `app.use` |
|
||
| `client/src/router/index.ts` | 删 `name: 'hermes.codingAgents'`(L160-164)及其路由块 |
|
||
| `AppSidebar.vue` | 删 L262-269 的导航项 |
|
||
| `components/hermes/usage/AgentBreakdown.vue` | 删 ekko/coding agent 分组渲染分支 |
|
||
| `components/hermes/chat/SessionListItem.vue` | 删代理类型图标分支 |
|
||
| `components/hermes/chat/ChatInput.vue` / `ChatPanel.vue` / `MessageList.vue` / `HistoryMessageList.vue` | 删 `coding_agent_id` 相关 UI 分支 |
|
||
| `stores/hermes/chat.ts` | 删 agent 选择器状态与 setter |
|
||
| `shared/session-display.ts` | 删代理类型标签 |
|
||
| `components/hermes/workflow/types.ts`、`WorkflowAgentNode.vue`、`views/hermes/WorkflowView.vue`、`views/hermes/HistoryView.vue` | 删 `coding_agent_id` 字段与节点类型 |
|
||
| `services/workflow-manager.ts` | 删 `coding_agent_id` 持久化 |
|
||
| `services/usage-recorder.ts` | 删 ekko/coding agent 用量归类 |
|
||
| `services/hermes/run-chat/{types,session-command,load-state,abort}.ts` | 删 `ChatCodingAgentId` 与相关分支 |
|
||
| `controllers/hermes/sessions.ts` | 删代理相关字段 |
|
||
|
||
### 5.3 run-chat dispatch 简化
|
||
|
||
改造 [run-chat/index.ts](file:///Users/jack/source/OtherProjectTemp/ekko-studio/packages/server/src/services/hermes/run-chat/index.ts#L467-L496):
|
||
|
||
```ts
|
||
// 删 import handleCodingAgentRun / handleEkkoAgentRun
|
||
// 删 isCodingAgentExecution / isEkkoAgentExecution 两个函数
|
||
// 删末尾的两条 dispatch 分支,handleBridgeRun 之后直接结束
|
||
```
|
||
|
||
### 5.4 isWorking 判定的连带修改(关键)
|
||
|
||
`isCodingAgentExecution` 被三处用于 `state.isWorking`:
|
||
|
||
| 行 | 原逻辑 | 改后 |
|
||
|---|---|---|
|
||
| L289 | `state.isWorking = !isCodingAgentExecution(source, data)` | `state.isWorking = true` |
|
||
| L423 | `if (!isCodingAgentExecution(source, data)) { ... }` | `if (true) { ... }` 或直接去掉条件 |
|
||
| L707 | `state.isWorking = !isCodingAgentExecution(source, data)` | `state.isWorking = true` |
|
||
|
||
**不要留 `isCodingAgentExecution` 空壳函数**。这是典型的"为兼容而留的开关",直接删。
|
||
|
||
### 5.5 Phase 2 验收
|
||
|
||
```bash
|
||
npm run test && npm run build
|
||
# 手工:聊天发一条消息 → 正常流式返回
|
||
# 手工:全局 Agent 跑一条 → 走桥正常
|
||
# 手工:群聊多 agent → 正常
|
||
```
|
||
|
||
风险:`load-state.ts` 与 `session-store.ts` 里历史会话可能存有 `coding_agent_id`。读侧改成"读到就忽略"即可,**不做数据迁移**。
|
||
|
||
---
|
||
|
||
## 6. Phase 3 — 砍桌面端 + 官网
|
||
|
||
### 6.1 删除
|
||
|
||
```
|
||
packages/desktop/ # 整个包
|
||
packages/website/ # 整个包
|
||
.github/workflows/desktop-release.yml
|
||
.github/workflows/desktop-manual-build.yml
|
||
.github/workflows/desktop-mac-update-manifest.yml
|
||
.github/workflows/desktop-runtime.yml
|
||
.github/workflows/website-deploy.yml
|
||
tsconfig.website.json
|
||
```
|
||
|
||
### 6.2 根 package.json scripts 清理
|
||
|
||
删:`desktop:install`、`desktop:prepare-runtime`、`desktop:prepare-python`、`desktop:dev`、`build:desktop`、`build:desktop:mac`、`build:desktop:win`、`build:desktop:linux`、`dev:website`、`build:website`、`preview:website`、`mcu:*`(若不保留 esp32)。
|
||
|
||
保留:`start`、`dev`、`dev:client`、`dev:server`、`build`、`harness:check`、`preview`、`test`、`test:watch`、`test:coverage`、`test:e2e`、`test:e2e:ui`、`openapi:generate`。
|
||
|
||
**删 `claude` script**(`claude --dangerously-skip-permissions` 是 I 组的配套)。
|
||
|
||
### 6.3 bin 目录
|
||
|
||
`bin/hermes-web-ui.mjs`、`bin/hermes-studio-mcp.mjs`、`bin/hermes-web-ui-mcp.mjs` → 重命名为 `bin/hermes-ui.mjs` + `bin/hermes-ui-mcp.mjs`,内部引用同步改。
|
||
|
||
### 6.4 server 侧清理
|
||
|
||
| 文件 | 改动 |
|
||
|---|---|
|
||
| `index.ts` | 删 `registerDesktopShutdownRoute`(L122-160)、`desktopShutdownHandler` 变量与 L397 赋值、L105 的 `isDesktopEnv()`。**注意 L397 的 `bindShutdown` 还要保留给正常关停用** |
|
||
| `services/shutdown.ts` | L19 的 `desktop` 分支删除,保留主流程 |
|
||
| `controllers/auth.ts` | L65 `requiresCredentialChange: process.env.HERMES_DESKTOP === 'true'` → 改为常量 `false` 或直接删该字段 |
|
||
| `services/hermes/gateway-autostart.ts` | 删 `shouldRecoverWindowsDesktopGatewayOrphans`(L156-163)及其在 index.ts 的调用 |
|
||
| `services/hermes/agent-bridge/manager.ts` | L321 `isDesktopEnv()` 删除 |
|
||
| `services/hermes/studio-mcp-autoinject.ts` | L72 同上 |
|
||
| `services/hermes/agent-bridge/python/bridge_runtime.py` | **L74 / L119 的 `HERMES_DESKTOP` 判断保留不动**。这是 Windows 下隐藏控制台窗口的逻辑,删掉会导致 Windows 上 git 子进程弹黑窗。见 §9 红线 |
|
||
|
||
### 6.5 client 侧清理
|
||
|
||
| 文件 | 改动 |
|
||
|---|---|
|
||
| `utils/desktop-bridge.ts` | 整个文件删除 |
|
||
| `App.vue` | 删 `desktopBridge` import、`isDesktopShell` / `isDesktopPetRoute` / `hasDesktopTitleBar`、`DesktopTitleBar` 组件、`WebPet` |
|
||
| `main.ts` | 删 `desktopBridge` 调用(L8/L20) |
|
||
| `router/index.ts` | 删 L180-190 的 `hermesDesktop` 注入逻辑 |
|
||
| `utils/completion-notification.ts` | 删本地 `desktopBridge` 副本(L19/L38-40/L80/L105) |
|
||
| `api/client.ts` | 删 L8/L14-15 |
|
||
| `components/layout/AppSidebar.vue` | 删 L29 |
|
||
| `components/layout/DesktopTitleBar.vue` | 整个文件删除 |
|
||
| `components/auth/DefaultCredentialPrompt.vue` | 删 L23 |
|
||
| `views/hermes/DesktopPetView.vue` | 删除 |
|
||
|
||
### 6.6 gateway 自启零迁移(§1.2 已核实)
|
||
|
||
**不需要任何迁移工作**。`ensureProfileGatewaysRunning()` 已在 Koa 启动钩子里。只需删掉 `HERMES_DESKTOP` 相关的 Windows 孤儿回收分支。
|
||
|
||
### 6.7 hermes CLI 改为自装
|
||
|
||
砍桌面端后 `hermes` 不再捆绑。改造点全部集中在 [hermes-process.ts](file:///Users/jack/source/OtherProjectTemp/ekko-studio/packages/server/src/services/hermes/hermes-process.ts) 与 [hermes-path.ts](file:///Users/jack/source/OtherProjectTemp/ekko-studio/packages/server/src/services/hermes/hermes-path.ts):
|
||
|
||
- `resolveHermesBin()` 已经是 `HERMES_BIN` → `'hermes'` 的优先级链,**保持不变**
|
||
- 删 `bundledCliPythonForWindows()`(L20-28)里的捆绑运行时假设,改为:`HERMES_BIN` 指向 `hermes.exe` 时,在同级/上级找 `python.exe`,找不到就用 `hermes.exe` 直调(hermes 官方 Windows 包自带 launcher,不一定需要 `-m hermes_cli.main`)
|
||
- 新增:启动时探测 `hermes` 是否在 PATH,不在则前端显示引导页("请安装 hermes-agent,或设置 `HERMES_BIN` 环境变量")
|
||
- **所有 CLI 调用继续走 `execHermesWithBin` / `spawnHermesWithBin`**,参数数组,禁止 shell 拼接(红线)
|
||
|
||
### 6.8 Phase 3 验收
|
||
|
||
```bash
|
||
npm run test && npm run test:e2e && npm run build
|
||
# 手工:起服务 → 自动拉起 gateway → 聊天正常
|
||
```
|
||
|
||
风险:**Windows 用户体验**。桌面端原本把 Python + hermes 一起打包,砍掉后 Windows 用户必须自己装 Python + hermes-agent。这是既定决策,但引导文案必须写清楚,否则第一启动就是白屏 + 一堆报错。
|
||
|
||
---
|
||
|
||
## 7. Phase 4 — ArkScope vendor + 样板页(风格基线)
|
||
|
||
### 7.1 ArkScope vendor 方式
|
||
|
||
**不作为 npm 依赖,不 clone 整仓**。322MB 里 131 个路径是游戏美术资源,全进项目是灾难。
|
||
|
||
**做法**:
|
||
|
||
1. 定位上游 commit(`pushed_at` 2026-09-16,`default_branch` = `main`),记录到 `packages/client/src/vendor/arkscope/PROVENANCE.md`
|
||
2. **只 vendor 2 个组件**:
|
||
- `ScrambleTitle`(文字解码动画)—— 纯 DOM + CSS,无外部素材
|
||
- `IsometricWave`(类亚克力 hover)—— CSS filter + 位移,无外部素材
|
||
3. 各自单独放到 `packages/client/src/vendor/arkscope/<ComponentName>/`,保留原文件头注释 + 上游 commit hash
|
||
4. **剥离** `useAssetPreloader` / `particle3DModels` / `data/componentRegistry.js` / `router` / `views` / `showcases` —— 这些是上游 demo 工程的东西,与组件无关
|
||
5. **不搬**:`src/assets/**`、`public/**`、`src/style.css` 全局样式(只取组件 scoped 样式)
|
||
|
||
**PROVENANCE.md 必须写明**:上游无 LICENSE,仅个人自用,不要分发。
|
||
|
||
### 7.2 使用边界(硬约束)
|
||
|
||
| 允许 | 禁止 |
|
||
|---|---|
|
||
| 登录页标题区装饰位面 | 聊天页(消息区、输入区、侧边栏) |
|
||
| Journey 图谱的背景层 | 任何表单页(Skills / Profiles / Settings / Models) |
|
||
| 首屏 loading / 空状态 | 任何表格页(Usage / Logs / Jobs / Kanban) |
|
||
| | 任何需要点击交互密集的区域 |
|
||
|
||
**判定标准**:装饰位面不得承载信息、不得承载交互、不得影响可读性。**鼠标穿透**(`pointer-events: none`)是硬要求。
|
||
|
||
### 7.3 样板页(风格基线)
|
||
|
||
Phase 4 交付 1 个样板页 + 1 个样板组件,用于锁定视觉语言。**在这两个定稿前不碰任何其他页面。**
|
||
|
||
#### 7.3.1 主题令牌
|
||
|
||
重写 `styles/theme.ts` → `styles/arco-theme.ts`,用 Arco 的 token 体系:
|
||
|
||
```
|
||
// 保留旧版克制灰阶的思路,但换成 Arco 变量
|
||
colorPrimary #2f2f2f (旧版 #333333 的延续)
|
||
colorBgLayout #fafafa / #1a1a1a
|
||
colorBgContainer #ffffff / #2a2a2a
|
||
borderRadius 6px
|
||
fontFamily Inter, system-ui, sans-serif
|
||
fontFamilyMono JetBrains Mono, Fira Code, monospace
|
||
```
|
||
|
||
**暗色模式**用 `body[arco-theme='dark']` + CSS 变量覆盖,而不是 Arco 的 `dark` theme + overrides 双轨(旧版 [App.vue](file:///Users/jack/source/OtherProjectTemp/ekko-studio/packages/client/src/App.vue#L23-L24) 的 `naiveTheme` computed 删掉)。
|
||
|
||
`index.html` 的 FOUC 脚本保留机制(读 localStorage 决定 class),改为切 `arco-theme` 属性。
|
||
|
||
#### 7.3.2 样板页:`LoginView.vue`
|
||
|
||
选它的理由:只用到输入框 + 按钮 + 少量文本,是**最小可控面**,且是 ArkScope 装饰位面的合法落点。
|
||
|
||
#### 7.3.3 样板组件:`AppSidebar.vue`
|
||
|
||
选它的理由:它是全站导航唯一入口,Arco 的 `Menu` / `Layout.Sider` 语义在这里定型后,其余 20+ 视图的导航/布局写法全部照抄。
|
||
|
||
**注意**:`AppSidebar.vue` 里也有大量 naive-ui 引用,迁移它等于验证"深层文件 + 条件渲染(`v-if="isSuperAdmin"`)"这类最难场景。
|
||
|
||
### 7.4 Arco 迁移映射表(Phase 4 建立,Phase 5/6 执行)
|
||
|
||
先建映射再改,不要边改边查。
|
||
|
||
| Naive UI | Arco Design Vue | 备注 |
|
||
|---|---|---|
|
||
| `NConfigProvider` | `ConfigProvider`(或直接 body 属性) | 暗色走 CSS 变量,不用它 |
|
||
| `NMessageProvider` / `useMessage` | `Message` | API 不兼容,需包一层 composable |
|
||
| `NDialogProvider` / `useDialog` | `Modal` | 需 composable 包装 |
|
||
| `NNotificationProvider` / `useNotification` | `Notification` | 需 composable 包装 |
|
||
| `NButton` | `a-button` | prop 名基本一致 |
|
||
| `NInput` | `a-input` / `a-textarea` | `type=textarea` → 独立组件 |
|
||
| `NSelect` | `a-select` | `options` 语义不同,需转换 |
|
||
| `NDataTable` | `a-table` | **列定义 API 差异最大,重点** |
|
||
| `NModal` | `a-modal` | `v-model:show` 一致 |
|
||
| `NDrawer` | `a-drawer` | |
|
||
| `NPopover` / `NTooltip` | `a-popover` / `a-tooltip` | trigger 语义有差异 |
|
||
| `NSwitch` | `a-switch` | |
|
||
| `NTag` | `a-tag` | `bordered` 无对应,用 `: bordered` style |
|
||
| `NCard` | `a-card` | |
|
||
| `NProgress` | `a-progress` | |
|
||
| `NEmpty` | `a-empty` | |
|
||
| `NCollapse` | `a-collapse` | |
|
||
| `NTabs` | `a-tabs` | |
|
||
| `NForm` / `NFormItem` | `a-form` / `a-form-item` | 校验规则 API 不同,需适配 |
|
||
| `NGrid` / `NGridItem` | `a-row` / `a-col` | |
|
||
| `NIcon` | `<Icon />` + `@arco-design/web-vue/es/icon` | 需全局注册图标 |
|
||
| `NLayout` / `NLayoutSider` | `a-layout` / `a-layout-sider` | |
|
||
| `NScrollbar` | `a-scrollbar` | |
|
||
| `NTimeline` | `a-timeline` | |
|
||
| `NUpload` | `a-upload` | |
|
||
| `NTree` | `a-tree` | 结构差异大 |
|
||
|
||
**全局 Provider 方案**:在 `main.ts` 用 `app.use(ArcoVue)` 全量注册(弃用 tree-shaking),换取迁移速度。后期如在意包体再优化。
|
||
|
||
**Message / Dialog / Notification 是最大风险**:Naive 的 `useMessage()` 是 hook,Arco 的 `Message.info()` 是命令式。需要写 `composables/useMessage.ts` / `useDialog.ts` / `useNotification.ts` 三个适配层,内部用模块级单例引用。全仓约 200+ 处调用。
|
||
|
||
### 7.5 Phase 4 验收
|
||
|
||
- 登录页渲染正常,明暗切换无闪烁,ArkScope 位面只在登录页出现且鼠标穿透
|
||
- 侧边栏菜单全部可用(可点进各视图,视图本身还没迁移,允许样式不完美)
|
||
- `npm run dev` 无 console 报错
|
||
- 记录 `docs/ui-baseline.md`:定稿的色板、圆角、间距、字体、组件用法约定
|
||
|
||
---
|
||
|
||
## 8. Phase 5 / 6 — Arco 批量迁移
|
||
|
||
### 8.1 Phase 5:聊天页(优先)
|
||
|
||
**落点**:
|
||
```
|
||
views/hermes/ChatView.vue
|
||
components/hermes/chat/ChatPanel.vue
|
||
components/hermes/chat/ChatInput.vue
|
||
components/hermes/chat/MessageList.vue
|
||
components/hermes/chat/MessageItem.vue
|
||
components/hermes/chat/SessionSearchModal.vue
|
||
components/hermes/chat/FilesPanel.vue
|
||
components/hermes/chat/HistoryMessageList.vue
|
||
stores/hermes/chat.ts
|
||
```
|
||
|
||
**为什么先做聊天页**:它是全站唯一的 Socket.IO 流式实时页,含审批弹窗、工具轨迹、思考块、Markdown 渲染、虚拟滚动、附件上传。最难的坑在这里踩完,后面 20 个 CRUD 页就是纯体力活。
|
||
|
||
**已知高风险点**:
|
||
- **虚拟滚动** `vue-virtual-scroller` 与 Arco 表格/布局的配合(`message-list-scroll-position` 有测试)
|
||
- **流式增量渲染**:`MessageItem.vue` 每次 token 到达都 re-render,Arco 组件如果包裹在消息气泡里会引入不必要的 diff 开销。**消息气泡内部尽量用原生 HTML,不用 Arco 组件**
|
||
- **审批/澄清弹窗**:时序敏感(必须打断流式),Arco Modal 的 v-model 与流式状态竞争要测
|
||
- **Mermaid 渲染超时**(有 `markdown-rendering-mermaid-import-timeout.test.ts`)
|
||
|
||
**验收**(必须逐条走):
|
||
- 发消息 → 流式输出 → 完成
|
||
- 工具调用轨迹展开/收起
|
||
- 审批请求弹出 → 选择 → 继续
|
||
- 澄清请求 → 回答
|
||
- 中断(stop)
|
||
- 重新生成 / 分支
|
||
- 附件上传 + 引用
|
||
- Markdown / 代码块 / KaTeX / Mermaid
|
||
- 多标签页同时开着(`chat-session-multitab.spec.ts`)
|
||
- 断线重连(`chat-run-reconnect.test.ts`)
|
||
|
||
### 8.2 Phase 6:其余 20 视图
|
||
|
||
**按耦合度分批**,每批独立提交:
|
||
|
||
| 批次 | 视图 | 特征 |
|
||
|---|---|---|
|
||
| 6a | `SettingsView` `ProfilesView` `ModelsView` `LogsView` | 纯表单 + 表格,最简单 |
|
||
| 6b | `SkillsView` `PluginsView` `McpManagerView` `MemoryView` | 卡片列表 + 抽屉 |
|
||
| 6c | `FilesView` `TerminalView` | 大量 DOM 操作与 xterm,注意别把 Arco 塞进来 |
|
||
| 6d | `UsageView` `PerformanceView` `SkillsUsageView` `JourneyView` | 图表/图谱 + 大量数据表格 |
|
||
| 6e | `KanbanView` `JobsView` `WorkflowView` `DevicesView` | 拖拽 + 复杂交互 |
|
||
| 6f | `ChannelsView` `GroupChatView` `GlobalAgentView` | IM 频道 + 群聊 + 全局 Agent |
|
||
| 6g | `HistoryView` `VersionPreviewView` | 历史会话(含 §5.2 的代理字段清理) |
|
||
|
||
**每批的完成定义**:该批视图内 `grep -c "naive-ui"` 归零 + `npm run test:client` 通过 + e2e 对应用例通过 + 明暗双主题人工过一遍。
|
||
|
||
**Phase 6 收尾**:
|
||
- `package.json` 删 `naive-ui` 依赖
|
||
- [vite.config.ts](file:///Users/jack/source/OtherProjectTemp/ekko-studio/vite.config.ts#L74-L75) 的 `manualChunks` 里 `naive-ui → ui-vendor` 改为 `arco-design → ui-vendor`;`optimizeDeps.include` 同步改
|
||
- `styles/variables.scss` 与 `theme.ts` 的对齐测试([style-system.test.ts](file:///Users/jack/source/OtherProjectTemp/ekko-studio/tests/client/style-system.test.ts))断言的是 Naive 的 key,需重写为 Arco token 断言
|
||
- 恢复 `package.json` 的 `prepare` script
|
||
- `AGENTS.md` 的前端规则改为"使用 Arco Design Vue,新增控件优先 `@arco-design/web-vue/es/icon`"
|
||
|
||
---
|
||
|
||
## 9. 绝对不能动(红线)
|
||
|
||
### 9.1 `packages/server/src/services/hermes/agent-bridge/python/` — 只读 vendored
|
||
|
||
**6 个文件**:`bridge_server.py`、`bridge_broker.py`、`bridge_pool.py`、`bridge_runtime.py`、`bridge_transport.py`、`hermes_bridge.py`
|
||
|
||
**动之前必须先看懂 `bridge_pool.py`**:
|
||
- `SessionDbHolder`(L76-105):按路径缓存 `SessionDB` 实例,**进程内单例复用**,这是性能关键
|
||
- `RunRecord`(L108+):run 生命周期记录
|
||
- `_bind_session_workspace_cwd`(L46-64):把 session 绑到工作区 cwd,**同时写 `register_task_env_overrides`**,改错会让所有工具在错误目录执行
|
||
|
||
**唯一例外**:`bridge_runtime.py` L74 / L119 的 `HERMES_DESKTOP` 判断**保留**(Windows 隐藏控制台窗口)。新项目虽然是 Web 端,但 Windows 用户从命令行起 Node 仍会弹 git 黑窗。
|
||
|
||
### 9.2 `/chat-run` Socket.IO 事件契约
|
||
|
||
**不得改动事件名与 payload 语义**。客户端 store 与 `run-chat/` 一一对应,改一边必须同步另一边,且要遵守 §11.2 的链路片段规则。
|
||
|
||
**允许**:在事件 payload 上**加新字段**(可选,客户端按需读取)。
|
||
**禁止**:改事件名、改字段名、改字段类型、改 `run.started` / `run.output` / `run.completed` / `run.failed` / `approval.request` / `clarify.request` 的触发时机。
|
||
|
||
### 9.3 hermes `state.db` 只读
|
||
|
||
`~/.hermes/**/state.db` 由 hermes 本体拥有。
|
||
|
||
- **我们的 SQLite**(`packages/server/src/db/`)是会话/消息/用量/工作流的**唯一可写**存储
|
||
- **不做启动时导入同步**(旧版有过往迁移逻辑,新项目不要引入)
|
||
- **profile 隔离靠注入 `HERMES_HOME`**,不靠复制目录
|
||
- Node 侧**任何**代码不得 `open()` hermes 的 `state.db`。需要读会话历史时走桥的 `getHistory` / `getOutput`,不直接读文件
|
||
|
||
### 9.4 其他
|
||
|
||
- `services/hermes/hermes-process.ts` 的 `execHermesWithBin` / `spawnHermesWithBin` 是唯一 CLI 出口,**禁止 shell 字符串拼接**
|
||
- `services/hermes/group-chat/` 与 `lib/context-compressor/`、`services/hermes/context-engine/` 同属聊天链路,改动受 §11.2 约束
|
||
- 本地 API 路由必须注册在 proxy 兜底路由**之前**([routes/index.ts](file:///Users/jack/source/OtherProjectTemp/ekko-studio/packages/server/src/routes/index.ts#L78) 注释)
|
||
|
||
---
|
||
|
||
## 10. 测试与 CI 策略
|
||
|
||
### 10.1 测试分层
|
||
|
||
| 层 | 位置 | 覆盖 |
|
||
|---|---|---|
|
||
| 单元 | `tests/server`、`tests/client` | service / store / 纯函数 |
|
||
| 契约 | `tests/server/chat-run-baseline.test.ts`、`group-chat-*-baseline.test.ts` | `/chat-run` 事件序列、群聊路由 |
|
||
| 端到端 | `tests/e2e` | Playwright + mock 后端 |
|
||
|
||
### 10.2 随 Phase 调整的测试
|
||
|
||
| Phase | 测试动作 |
|
||
|---|---|
|
||
| 0 | 全量拷贝,作为回归基线 |
|
||
| 1 | 改 `pwa-metadata.test.ts`;`i18n-coverage.test.ts` 收敛到 2 语言 |
|
||
| 2 | 删 I/J 组全部测试;`chat-run-baseline.test.ts` 补"无 coding agent 分支"断言 |
|
||
| 3 | 删 desktop 相关;e2e 中 desktop 用例移除 |
|
||
| 4 | 新增 `arkscope-vendor.test.ts`:断言 vendor 目录无游戏素材文件、无 `src/assets` 引用 |
|
||
| 5 | 保留全部 chat 相关测试;新增 `message-item-arko.test.ts` |
|
||
| 6 | 每批视图补一个 `*-view.test.ts`;`style-system.test.ts` 重写为 Arco token 断言 |
|
||
|
||
**新增机械保障**(建议):
|
||
- `tests/client/no-naive-ui.test.ts`:递归扫 `packages/client/src`,任何文件 `import ... from 'naive-ui'` 即失败。这是换库不回流的最强保障。
|
||
- `tests/client/i18n-parity.test.ts`:zh 与 en 的 key 集合必须完全一致。
|
||
|
||
### 10.3 CI
|
||
|
||
**保留 workflow**:`build.yml`、`playwright.yml`、`npm-lockfile-check.yml`、`docker-publish.yml`
|
||
**删除**:`desktop-*`(4 个)、`website-deploy.yml`
|
||
**新建或改造** `build.yml`:
|
||
|
||
```yaml
|
||
- npm ci --ignore-scripts
|
||
- npm run harness:check
|
||
- npm run test:coverage
|
||
- npm run test:e2e
|
||
- npm run build
|
||
```
|
||
|
||
`fetch-depth: 0` 必须保留(harness:check 靠 git diff 判断链路变更)。
|
||
|
||
### 10.4 harness-check.mjs 重写
|
||
|
||
现有 [harness-check.mjs](file:///Users/jack/source/OtherProjectTemp/ekko-studio/scripts/harness-check.mjs#L246-L488) 有 **170+ 行在断言 desktop/website 的产物与文案**(desktop-release.yml 的 dmg/exe/AppImage、installer.nsh 的 `Stop-Process`、updater 的 `download.ekkolearnai.com`、`packages/desktop/build/icons/` 的 11 个图标文件…)。**必须整体重写,不是删几行。**
|
||
|
||
新 harness-check 应校验:
|
||
1. 必需文件存在:`AGENTS.md`、`ARCHITECTURE.md`、`DEVELOPMENT.md`、`docs/harness/*`
|
||
2. 必需目录存在:`packages/client/src`、`packages/server/src`、`packages/skills`、`tests/{client,server,e2e,shared}`、`.github/workflows`
|
||
3. **禁止目录不存在**:`packages/desktop`、`packages/website`、`packages/ekko-agent`(防回流)
|
||
4. `AGENTS.md` ≤ 120 行,且链接上述文档
|
||
5. `package.json` 有 `harness:check` / `test` / `test:coverage` / `test:e2e` / `build`
|
||
6. `ARCHITECTURE.md` 记录了 `HERMES_WEB_UI_HOME`(保留决策)
|
||
7. **禁止字符串扫描**:`packages/`、`tests/`、`scripts/`、`bin/` 内不得出现 `ekko` / `hermes-web-ui`(这是 §4.1 判定的机械化)
|
||
8. Chat 链路变更片段规则(保留,但清单去掉 coding-agents 相关)
|
||
9. `build.yml` 含 `npm run harness:check` 与 `fetch-depth: 0`
|
||
|
||
---
|
||
|
||
## 11. 风险登记
|
||
|
||
| # | 风险 | 影响 | 缓解 |
|
||
|---|---|---|---|
|
||
| R1 | Arco 迁移面 100 个文件,工作量远超预期 | 工期失控 | Phase 4 先出映射表;6a→6g 分批;每批可独立停下来 |
|
||
| R2 | `Message` / `Dialog` / `Notification` 全局 hook → 命令式 API | 200+ 调用点 | 先写 3 个 composable 适配层并冻结,批内只调用适配层 |
|
||
| R3 | 流式消息气泡内混入 Arco 组件 → 性能退化 | 聊天卡顿 | 气泡内禁用 Arco 组件;Phase 5 用 e2e 测流式延迟 |
|
||
| R4 | ArkScope 上游无 LICENSE 且强绑游戏素材 | 法律风险 + 素材不可用 | 只 vendor 2 个无素材组件;PROVENANCE.md 标注;仅自用不分发 |
|
||
| R5 | `harness-check.mjs` 重写不彻底 | CI 红灯或漏检 | 重写后手工核对每一处断言的必要性 |
|
||
| R6 | `state.db` 语义被误解导致双写 | 数据损坏 | §9.3 写进 `AGENTS.md`;新增测试断言 Node 侧无 hermes db 打开 |
|
||
| R7 | Windows 用户失去捆绑 Python/hermes | 首次启动白屏 | §6.7 引导页;README 显著位置写安装步骤 |
|
||
| R8 | `update.ts` 在线更新在未发布 npm 前失效 | 用户点了报错 | Phase 1 就把入口文案改为"源码运行模式" |
|
||
| R9 | `nodemon.json` watch 残留 `packages/ekko-agent/src` | 删包后 dev 启动异常 | Phase 2 一并改 |
|
||
| R10 | e2e fixture 依赖被砍的 API | `test:e2e` 红 | 每批 Phase 2/3 后必跑 e2e |
|
||
|
||
---
|
||
|
||
## 12. 执行顺序建议
|
||
|
||
```
|
||
Phase 0 骨架 → npm ci && npm run build 通过
|
||
Phase 1 去品牌 + i18n → grep 双零 + build 通过
|
||
Phase 2 砍 I/J 组 → 聊天/全局/群聊三条链路验证通过
|
||
Phase 3 砍桌面+官网 → e2e 全绿 + 网关自启验证
|
||
↓ 此时项目功能完整,只是界面还是旧的
|
||
Phase 4 ArkScope + 样板页 → docs/ui-baseline.md 定稿
|
||
Phase 5 聊天页 → 聊天全流程对等
|
||
Phase 6 6a→6g 批量 → 无 naive-ui 残留
|
||
Phase 7 测试/CI 收口 → harness:check 重写 + CI 绿
|
||
```
|
||
|
||
**Phase 0-3 是"能跑",Phase 4-6 是"好看"。不要在 1-3 阶段碰任何样式代码**——去品牌和砍功能时改样式,等于让 diff 审查失效。
|
||
|
||
---
|
||
|
||
## 13. 待你确认
|
||
|
||
1. **Phase 1-3 是否拆成 3 个独立 git 仓库历史**,还是合成一条线性历史?(旧版有 `docs/chat-chain-changes/` 的 PR 片段传统,影响 harness:check 的 diff 检测)
|
||
2. **`packages/esp32-c3` 是否保留**?本蓝图按"砍掉"写。若你要做 ESP32 语音硬件(O 组),需要保留并把 `mcu:*` scripts 加回。
|
||
3. **`hermes-ui` 是否要发布到 npm**?决定 `update.ts` 在线更新逻辑是修好还是标注不可用。
|