remove the desktop-pet system
Build / build (push) Canceled after 0s
Playwright / e2e (push) Canceled after 0s

The pet feature was three loosely coupled subsystems that no core flow
depended on: the Petdex catalog page, the pet install/preference store, and
the pet-state socket. All three are removed.

The only cross-boundary touch point was a try/catch-wrapped observer that
mapped chat-run events to pet animations. Removing it leaves the /chat-run
event contract unchanged: no event name, field name, field type, or emission
timing changed.

Removing petdexPublicRoutes also closes the unauthenticated outbound proxy
at /api/hermes/petdex/asset, which shrinks the SSRF surface.
This commit is contained in:
2026-10-20 13:24:17 +08:00
committed by trae-solo-agent
parent 5e1003ceb7
commit b709ec6742
30 changed files with 64 additions and 1793 deletions
+1 -1
View File
@@ -124,7 +124,7 @@
## P. 桌宠系统
- [ ] ❌ **整组砍(2026-10-15 确认)**:桌宠状态 socket、Petdex 图鉴、pets store、PetdexView 全删(浪费资源)
- [x] ❌ **整组砍(2026-10-15 确认,2026-10-20 执行)**:桌宠状态 socket、Petdex 图鉴、pets store、PetdexView 已全删(浪费资源)
## Q. 编程代理之外的特色杂项
@@ -0,0 +1,59 @@
---
date: 2026-10-20
pr: pending
feature: Remove the desktop-pet system (pet-state socket, Petdex catalog, pets store)
impact: The optional "宠物" sidebar entry and the whole pet subsystem are gone. The only cross-boundary touch point was a try/catch-wrapped observer that mapped chat-run events to pet animations; removing it does not change any /chat-run event name, field name, field type, or emission timing. No chat behavior changed.
---
# Remove the desktop-pet system
## What changed
The pet feature was three loosely coupled subsystems that no core flow
depended on. All three are removed.
| Area | Removed |
| --- | --- |
| Client | `views/hermes/PetdexView.vue`, `stores/hermes/pets.ts`, `stores/hermes/pet-state.ts`, `api/hermes/pets.ts`, `api/hermes/petdex.ts`, `api/hermes/pet-state.ts`, `public/icons/pet-resize.svg` (orphan) |
| Client wiring | `router/index.ts` route `hermes.petdex`, `AppSidebar.vue` nav item, `sidebar.petdex` + `petdex.*` i18n keys in `zh.ts` / `en.ts` |
| Server | `services/hermes/pets.ts`, `services/hermes/petdex.ts`, `services/hermes/pet-state-socket.ts`, `controllers/hermes/pets.ts`, `controllers/hermes/petdex.ts`, `routes/hermes/pets.ts`, `routes/hermes/petdex.ts` |
| Server wiring | `routes/index.ts` (three `app.use` registrations), `index.ts` (`PetStateSocketServer` import, field, and `init()`) |
| Chat chain | `run-chat/index.ts` and `run-chat/handle-bridge-run.ts` pet observation calls, `resolvePetEventProfile`, `observePetEvent` |
| Tests | `tests/server/pets-service.test.ts`, `tests/server/petdex-service.test.ts`, `tests/client/pets-store.test.ts`, `/api/hermes/pets/active` mock in `tests/e2e/fixtures.ts` |
## Why it was safe
The pet subsystem sat on a single boundary crossing: the chat-run event
stream. `run-chat/index.ts` (`emitExternalEvent`, `emitToSession`) and
`run-chat/handle-bridge-run.ts` (two `emit` closures) each called
`observeRunChatPetEvent(profile, event, tagged)` to translate a chat event
into a pet animation state. Every call was wrapped in a `try/catch` that only
logged at `debug` level, so a pet failure could never break a run.
Removing those calls leaves the surrounding emit paths intact: the tagged
payload, the `session:<id>` room broadcast, the direct `socket.emit` fallback,
the waiter wake-ups, and the session event buffer are all unchanged.
Everything else was an island: the client `pets` store was consumed only by
`PetdexView`, and the client `pet-state` store had no callers at all — the
client never connected to the `/pet-state` namespace, so the server-side
`pet.state.snapshot` / `pet.state.updated` events had no consumer.
## Not changed
The `/chat-run` Socket.IO contract is untouched: no event name, field name,
field type, or emission timing changed. This fragment exists because the
touched files sit on the chat chain path, not because any chat behavior moved.
## Side effect
`routes/index.ts` registered `petdexPublicRoutes` before the auth middleware,
which exposed `/api/hermes/petdex/asset` as an unauthenticated outbound proxy
(with a `petdex.dev` host allowlist). Removing it closes that endpoint and
shrinks the SSRF surface.
## Local data
Persisted pet state lives under
`<HERMES_WEB_UI_HOME>/profile-metadata/<base64url(profile)>/pets/`. Deleting
the code does not remove those files; they can be deleted manually.
+3 -4
View File
@@ -66,7 +66,7 @@ CYBER 是本项目**唯一**的视觉语言。`docs/ui-baseline.md` 是它的**
| --- | --- | --- |
| **已落地** | `SettingsView.vue` | `cy-*` 骨架 + 令牌 |
| **已落地(无骨架)** | `LoginView.vue` | 令牌密度最高(24 处),装饰位面合规 |
| **部分落地** | `ChatView` / `GroupChatView` / `GlobalAgentView` / `HistoryView` / `JourneyView` / `WorkflowView` / `LogsView` / `PerformanceView` / `PluginsView` / `McpManagerView` / `MemoryView` / `PetdexView` / `TerminalView` / `SkillsView` / `SkillsUsageView` / `DevicesView` / `KanbanView` / `FilesView` / `HermesMissingView` | 用了基础令牌,但布局仍是 Arco 原生(`a-card` / `a-tabs`) |
| **部分落地** | `ChatView` / `GroupChatView` / `GlobalAgentView` / `HistoryView` / `JourneyView` / `WorkflowView` / `LogsView` / `PerformanceView` / `PluginsView` / `McpManagerView` / `MemoryView` / `TerminalView` / `SkillsView` / `SkillsUsageView` / `DevicesView` / `KanbanView` / `FilesView` / `HermesMissingView` | 用了基础令牌,但布局仍是 Arco 原生(`a-card` / `a-tabs`) |
| **未落地** | `JobsView` / `ModelsView` / `ProfilesView` / `UsageView` / `ChannelsView` / `VersionPreviewView` | style 块几乎没有色值,也没有语义色 |
**CYBER 目前是「孤岛式」的**:设置页 + 聊天链是两块完整的岛,其余 20+ 页面停留在迁移前原样。
@@ -170,7 +170,7 @@ CYBER 主题**完成**的定义是下面五条同时成立:
2. 按页面分批改,每批 3-5 个页面:
- **批次 A(数据展示型)**:`UsageView` / `JobsView` / `LogsView` / `ModelsView` / `ProfilesView`
- **批次 B(配置型)**:`DevicesView` / `ChannelsView` / `PluginsView` / `McpManagerView`
- **批次 C(内容型)**:`FilesView` / `MemoryView` / `PetdexView` / `SkillsView` / `SkillsUsageView`
- **批次 C(内容型)**:`FilesView` / `MemoryView` / `SkillsView` / `SkillsUsageView`
- **批次 D(复杂型)**:`WorkflowView` / `KanbanView` / `JourneyView` / `PerformanceView` / `HistoryView` / `HermesMissingView` / `VersionPreviewView`
3. 每批的替换模式:**Arco 结构 → `.cy-panel` 外壳**,但**保留** Arco 组件本身
(`a-table` / `a-form` / `a-select` 都不动)。Arco 组件的外观已经被
@@ -192,7 +192,7 @@ CYBER 主题**完成**的定义是下面五条同时成立:
| --- | --- | --- |
| A | `UsageView` / `JobsView` / `LogsView` / `ModelsView` / `ProfilesView` | 大部分已合规;`JobsView` 补 `cy-sec-t` 分节标题 + i18n key `jobs.sectionList` |
| B | `DevicesView` / `ChannelsView` / `PluginsView` / `McpManagerView` | `ChannelsView` 内容区包进 `cy-panel`;`McpManagerView` 已合规(modal 内列表保留自定义边框,避免卡片套卡片) |
| C | `FilesView` / `MemoryView` / `PetdexView` / `SkillsView` / `SkillsUsageView` | 已合规;`PetdexView` 棋盘格 `rgba(127,127,127,0.08)` → `rgba(var(--text-muted-rgb), 0.08)` |
| C | `FilesView` / `MemoryView` / `SkillsView` / `SkillsUsageView` | 已合规 |
| D | `WorkflowView` / `KanbanView` / `JourneyView` / `PerformanceView` / `HistoryView` / `HermesMissingView` / `VersionPreviewView` / `TerminalView` / `GlobalAgentView` | **全部已是令牌驱动**。这些是专用布局(画布 / 看板 / 终端 / 聊天流),原型的 `panel` 结构不适用,不需要套骨架类 |
**批次 D 的判定依据**:「cy-* 计数为 0」是**误报**。判断标准应是
@@ -274,7 +274,6 @@ CYBER 主题**完成**的定义是下面五条同时成立:
| 位置 | 问题 | 修法 |
| --- | --- | --- |
| `views/hermes/PetdexView.vue` | 棋盘格 `rgba(127,127,127,0.08)` | → `rgba(var(--text-muted-rgb), 0.08)` |
| `utils/hermes/kanban-status-colors.ts` | 分类色 `#c084fc` + `rgba(192,132,252,0.14)` 字面量 | 新增令牌 `--kanban-review` / `--kanban-review-rgb`;灰阶改走 `--text-muted-rgb` |
| `components/hermes/chat/MessageList.vue` | 浅色主题遗留阴影 `rgba(15,23,42,0.05)` | → `var(--shadow-sm)` |
+1 -1
View File
@@ -199,7 +199,7 @@
### 视觉细节
- **圆角 tag**:naive 的 `NTag round` 无 Arco 对应,改用了 `border-radius: 999px`(`PetdexView.vue`、`DevicesView.vue`)
- **圆角 tag**:naive 的 `NTag round` 无 Arco 对应,改用了 `border-radius: 999px`(`DevicesView.vue`)
- **按钮尺寸**:naive 的 `size="tiny"` → Arco `size="mini"`,可能与相邻元素不齐
- **滚动条**:naive 的 `:native-scrollbar="false"` 无对应,已删除,滚动条样式会变