254 lines
8.1 KiB
Markdown
254 lines
8.1 KiB
Markdown
# Phase 004 — 砍桌面端 + 官网 + 清理依赖
|
||
|
||
| 项 | 值 |
|
||
|---|---|
|
||
| 目标 | 无 Electron、无官网;hermes CLI 改用户自装;依赖表与 lockfile 一次性收干净 |
|
||
| 前置 | Phase 003 通过 |
|
||
| 产出 | `npm ci && npm run build && npm run test:e2e` 全绿;gateway 自启仍工作 |
|
||
| 参考 | `docs/03-施工蓝图.md` §6 |
|
||
|
||
---
|
||
|
||
## 0. 已核实:gateway 自启零迁移
|
||
|
||
原蓝图担心的「gateway 自启逻辑一半长在 Electron 里」**不存在**。
|
||
|
||
`packages/server/src/index.ts` 的 `startRuntimeServicesBeforeListen()` / `startRuntimeServicesAfterListen()` 已经调用 `ensureProfileGatewaysRunning()`。
|
||
|
||
Electron 侧只有两处:
|
||
1. `gateway-autostart.ts` 里 `shouldRecoverWindowsDesktopGatewayOrphans()` 依赖 `HERMES_DESKTOP`
|
||
2. 注册在 `/api/desktop/shutdown` 的关闭回调
|
||
|
||
**本 Phase 只删这两处,不做任何迁移。**
|
||
|
||
---
|
||
|
||
## 1. 功能任务 1 — 删除 desktop 与 website
|
||
|
||
Phase 001 已删掉 `packages/desktop` / `packages/website` / 相关 workflow。本 Phase 处理**引用方**。
|
||
|
||
### 1.1 根 `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
|
||
claude # I 组配套:claude --dangerously-skip-permissions
|
||
```
|
||
|
||
`mcu:*` 系列:Phase 001 已删 `esp32-c3`,这些 script 也要删。若你后续要做语音硬件,另开 Phase 恢复。
|
||
|
||
保留:`start` `dev` `dev:client` `dev:server` `build` `harness:check` `preview` `test` `test:watch` `test:coverage` `test:e2e` `test:e2e:ui` `openapi:generate`
|
||
|
||
### 1.2 server 侧
|
||
|
||
| 文件 | 改动 |
|
||
|---|---|
|
||
| `src/index.ts` | 删 `registerDesktopShutdownRoute` import 与调用、删 `desktopShutdownHandler` 变量与赋值、删 `isDesktopEnv()` |
|
||
| `src/index.ts` | **注意**:`bindShutdown` 主流程要保留,它也服务正常关停。只删桌面分支 |
|
||
| `services/shutdown.ts` | 删 `desktop` 分支,保留主流程 |
|
||
| `controllers/auth.ts` | `requiresCredentialChange: process.env.HERMES_DESKTOP === 'true'` → 改常量 `false` 或删该字段 |
|
||
| `services/hermes/gateway-autostart.ts` | 删 `shouldRecoverWindowsDesktopGatewayOrphans()` 及 index.ts 里对它的调用 |
|
||
| `services/hermes/agent-bridge/manager.ts` | 删 `isDesktopEnv()` 用法 |
|
||
| `services/hermes/studio-mcp-autoinject.ts` | 同上 |
|
||
|
||
### 1.3 client 侧
|
||
|
||
| 文件 | 改动 |
|
||
|---|---|
|
||
| `src/utils/desktop-bridge.ts` | **整个文件删除** |
|
||
| `src/App.vue` | 删 `desktopBridge` import、`isDesktopShell` / `isDesktopPetRoute` / `hasDesktopTitleBar`、`DesktopTitleBar` 组件、`WebPet` |
|
||
| `src/main.ts` | 删 `desktopBridge` 调用 |
|
||
| `src/router/index.ts` | 删 `hermesDesktop` 路由注入逻辑 |
|
||
| `src/utils/completion-notification.ts` | 删本地 `desktopBridge` 副本 |
|
||
| `src/api/client.ts` | 删对应 import 与分支 |
|
||
| `src/components/layout/AppSidebar.vue` | 删对应 import |
|
||
| `src/components/layout/DesktopTitleBar.vue` | **整个文件删除** |
|
||
| `src/components/auth/DefaultCredentialPrompt.vue` | 删 `desktopBridge` 相关 |
|
||
| `src/views/hermes/DesktopPetView.vue` | **整个文件删除** |
|
||
| `src/components/hermes/pets/WebPet.vue` | 若无其他引用则删;有引用先解引用 |
|
||
|
||
### 1.4 测试
|
||
|
||
```bash
|
||
rm -f tests/client/desktop-titlebar.test.ts
|
||
rm -f tests/client/app-web-pet.test.ts
|
||
```
|
||
|
||
e2e 里的 desktop 用例移除。
|
||
|
||
---
|
||
|
||
## 2. 功能任务 2 — hermes CLI 改用户自装
|
||
|
||
砍桌面端后 hermes 不再捆绑。改动全部集中在两个文件。
|
||
|
||
### 2.1 `hermes-path.ts`
|
||
|
||
`resolveHermesBin()` 已是 `HERMES_BIN` → `'hermes'` 的优先级链,**保持不变**。
|
||
|
||
改 `bundledCliPythonForWindows()`:删掉「找捆绑运行时」的假设,改为——
|
||
|
||
- `HERMES_BIN` 指向 `hermes.exe` 时,在同级 / 上级目录找 `python.exe`
|
||
- 找不到就用 `hermes.exe` 直调(hermes 官方 Windows 包自带 launcher,不一定需要 `-m hermes_cli.main`)
|
||
|
||
### 2.2 `hermes-process.ts`
|
||
|
||
- **不新增 shell 拼接**。所有调用继续走 `execHermesWithBin` / `spawnHermesWithBin`,参数数组
|
||
- 加一个 `isHermesCliAvailable()` 探测函数
|
||
|
||
### 2.3 引导页(用户可见)
|
||
|
||
启动时若探测不到 hermes CLI,前端显示引导:
|
||
|
||
```
|
||
未检测到 hermes CLI
|
||
|
||
请先安装:
|
||
pip install hermes-agent
|
||
|
||
或设置环境变量指定路径:
|
||
HERMES_BIN=/path/to/hermes
|
||
|
||
安装后重启本服务。
|
||
```
|
||
|
||
**中英双语都要写**(`zh.ts` + `en.ts`)。
|
||
|
||
落点建议:新增 `packages/client/src/views/hermes/HermesMissingView.vue`,在 `router/index.ts` 里作为前置守卫(与 `LoginView` 同级,登录前判断)。
|
||
|
||
---
|
||
|
||
## 3. 功能任务 3 — 依赖与 lockfile 收口
|
||
|
||
**这是本 Phase 最需要小心的部分**:`npm ci` 要求 `package.json` 与 `package-lock.json` 严格一致,任何增删都会让它失败。
|
||
|
||
### 3.1 删依赖
|
||
|
||
`package.json` 的 `dependencies` / `devDependencies` 删:
|
||
|
||
```
|
||
electron
|
||
electron-builder
|
||
@electron/*
|
||
electron-store
|
||
electron-updater (若 devDeps 里有)
|
||
```
|
||
|
||
先跑一次定位:
|
||
|
||
```bash
|
||
grep -n "electron" package.json
|
||
```
|
||
|
||
### 3.2 重生成 lockfile
|
||
|
||
```bash
|
||
# 删旧 lock,用当前 package.json 重装,版本不主动升级
|
||
rm -f package-lock.json
|
||
npm install --package-lock-only --ignore-scripts
|
||
```
|
||
|
||
`--package-lock-only` 只更新 lock 不装包,**不会升级已存在的版本**(依赖树解析会沿用现有版本范围)。
|
||
|
||
```bash
|
||
npm ci --ignore-scripts
|
||
npm run build
|
||
```
|
||
|
||
### 3.3 校验版本没被偷偷升级
|
||
|
||
```bash
|
||
# 对比新旧 lock 里几个关键包的版本
|
||
git diff package-lock.json | grep -E "^\+.*\"(vue|koa|socket.io|better-sqlite3|vite|pinia)\""
|
||
# 期望:无新增版本行
|
||
```
|
||
|
||
---
|
||
|
||
## 4. 功能任务 4 — Dockerfile / CI 同步
|
||
|
||
| 文件 | 改动 |
|
||
|---|---|
|
||
| `Dockerfile` | 删 electron 相关 build 步骤与产物拷贝 |
|
||
| `docker-compose.yml` | 删 electron 挂载 |
|
||
| `.github/workflows/build.yml` | 确认无 desktop 步骤 |
|
||
| `.github/workflows/webui-release.yml` | Phase 002 已去品牌,确认打包产物名已改 |
|
||
|
||
### 4.1 `fetch-depth: 0` 必须保留
|
||
|
||
`harness-check.mjs` 靠 `git diff` 判断链路变更。CI 里 `actions/checkout` 缺 `fetch-depth: 0` 会让检测失效。
|
||
|
||
---
|
||
|
||
## 5. 验收
|
||
|
||
### 5.1 命令
|
||
|
||
```bash
|
||
cd /Users/jack/source/MyProject/js/hermes-ui
|
||
|
||
grep -rn "desktop\|electron\|Electron" packages/ --include="*.ts" --include="*.vue" \
|
||
| grep -v "bridge_runtime.py"
|
||
# 期望:零命中(python 的 HERMES_DESKTOP 判断例外,见 §6)
|
||
|
||
grep -n "electron" package.json
|
||
# 期望:零命中
|
||
|
||
npm ci --ignore-scripts
|
||
npm run build
|
||
npm run test
|
||
npm run test:e2e
|
||
```
|
||
|
||
### 5.2 手工
|
||
|
||
- [ ] `npm run dev` 正常启动
|
||
- [ ] 启动后 gateway 自动拉起(看日志)
|
||
- [ ] 聊天正常
|
||
- [ ] 故意把 `HERMES_BIN` 指向不存在的路径 → 出现引导页而非白屏报错
|
||
- [ ] Docker 构建成功且容器内聊天正常
|
||
|
||
---
|
||
|
||
## 6. 红线:这两处 `HERMES_DESKTOP` **保留不动**
|
||
|
||
`packages/server/src/services/hermes/agent-bridge/python/bridge_runtime.py` L74 / L119:
|
||
|
||
这是 Windows 下隐藏子进程控制台窗口的逻辑。删掉会导致 Windows 用户运行 git / 命令时**弹黑窗**。
|
||
|
||
虽然新项目是 Web 端、不再有 Electron 壳,但 Windows 用户从命令行起 Node 依然会弹。
|
||
|
||
**判断依据**:这两个 env 在新项目里永远为 `undefined`,条件分支永不进入 → 逻辑上等价于删除,但**保留代码不影响正确性**,删除则影响。留。
|
||
|
||
---
|
||
|
||
## 7. 风险
|
||
|
||
| # | 风险 | 缓解 |
|
||
|---|---|---|
|
||
| P4-1 | 删 `bindShutdown` 时误伤正常关停 | 只删桌面分支,主流程保留;手工 Ctrl+C 验证一次 |
|
||
| P4-2 | lockfile 重生成时依赖被升级 | `git diff package-lock.json` 逐项确认,锁版本 |
|
||
| P4-3 | Windows 用户失去捆绑 Python | 引导页 + README 显著位置写安装步骤。这是既定决策 |
|
||
| P4-4 | e2e 有 desktop 用例残留 | `test:e2e` 必跑 |
|
||
| P4-5 | `WebPet.vue` 被多处引用 | 删前先 `grep -rn "WebPet"` |
|
||
| P4-6 | `DefaultCredentialPrompt` 在 auth.ts 有对应字段 | 两边一起改 |
|
||
|
||
---
|
||
|
||
## 8. 完成标志
|
||
|
||
**项目此时功能完整、界面还是旧的 Naive UI。** 进入 Phase 005。
|
||
|
||
从此开始才允许改样式代码。
|