--- date: 2026-10-17 pr: pending feature: Phase 006 - chat page naive-ui to Arco Design Vue rendering migration impact: No chat-chain behavior change; chat components only swap naive-ui components for Arco equivalents. Chat run flow, chat store logic, keyboard handling, and the /chat-run Socket.IO contract are untouched. --- # Phase 006 — Chat page Arco migration Phase: `docs/phases/phase_006.md` ## What Changed Rendering-layer only, across `packages/client/src/components/hermes/chat/`: - `ChatInput.vue` — `NPopselect` reasoning-effort picker and `NDropdown` settings menu became `a-dropdown` whose `#content` slot declares `a-doption` items; `NModal` became `a-modal` (`:footer="false"` for informational dialogs, custom `#footer` for confirm dialogs); `NInputNumber` became `a-input-number hide-button`. The two menu buttons use a native `:title` instead of `a-tooltip` because Arco Triggers cannot be nested. `useKeyboard` wiring and the textarea height auto-resize logic were not touched. - `ChatPanel.vue` — session context menu moved from `NDropdown trigger="manual"` to `a-dropdown trigger="contextMenu" align-point` wrapping `.session-items` (the three-level export submenu became nested `a-dsubmenu` / `a-doption`); 4 dialogs, the new-chat drawer, 5 `NSelect`, 6 `NTooltip`, and the `NPopconfirm` confirmations became Arco equivalents. - `MarkdownRenderer.vue` — the text preview `NDrawer`/`NDrawerContent` pair became a single `a-drawer`, and it is now lazily mounted behind `v-if="textPreviewVisible"`. The component's public interface is unchanged because it is reused by 8 call sites (including Phase 007's GroupMessageItem). - `MessageItem.vue` — the tool-change `NDrawer`/`NDrawerContent` became a single `a-drawer`. It uses `:visible` + `@update:visible` rather than `v-model:visible` so the existing "refuse to close with unsaved changes" guard still runs. - `MessageList.vue` — approval / clarification overlay buttons and inputs. - `FolderPicker.vue` — folder tree context menu moved to `a-trigger trigger="contextMenu" align-point` with an `#content` slot; `NModal preset="dialog"` became `a-modal` with a custom `#footer`. - `SessionListItem.vue`, `SessionSearchModal.vue`, `TerminalPanel.vue`, `FilesPanel.vue` — remaining buttons, checkboxes, tooltips, popconfirms, selects, and spinners. `VirtualMessageList.vue` already had no `NScrollbar` and keeps `vue-virtual-scroller` as the sole scroll owner (recorded as an exception in `docs/arco-mapping.md`). `stores/hermes/chat.ts`, `stores/hermes/files.ts`, and `ChatView.vue` needed no changes. ## Contract Check `/chat-run` event names, field names, field types, and emission timing are unchanged. No file under `packages/server/`, `services/hermes/group-chat/`, `lib/context-compressor/`, or `services/hermes/context-engine/` was modified, so no bridge, compressor, or context-engine behavior changed. The §1 red line (no Arco components inside the message bubble) is enforced by `tests/client/message-item-arko.test.ts`, which registers the real Arco plugin and asserts that no `.arco-*` element appears in the rendered bubble for assistant, user, and tool messages, including across streaming re-renders. ## Verification ```bash 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 npm run harness:check npm run test npm run test:e2e npm run build ``` Result: grep 0 across all chat files; 274 test files / 2026 tests passing; 35 e2e tests passing; harness check and build clean. ## Follow-up Fix Arco's `a-dropdown` has no `droplist` prop — its menu content must be declared in the `#content` slot with `a-doption` / `a-dsubmenu` children. The first migration pass used `:droplist`, which Arco silently ignored (unknown props fall through as plain attributes), so all three dropdowns opened an empty popup. Fixed by declaring the options in the `#content` slot, and locked down by `tests/e2e/chat-input-dropdown.spec.ts`, which asserts the reasoning effort menu (7 options, selection applied), the input settings menu (2 options, toggle applied), and the session context menu plus its export submenu. The §9.2 manual checklist rows that need a live run are covered by `tests/e2e/chat-rendering-smoke.spec.ts`: streamed deltas rendering bold text, inline code, a highlighted code block, KaTeX math, and a Mermaid diagram; the Stop button appearing on run start and clearing on `run.completed`; the "no Arco inside the bubble" red line; and the session model dialog plus session search opening from the chat UI.