- Vendor ArkScope decorative layers (ScrambleTitle / IsometricWave) with provenance notes; decorative-only per AGENTS.md red lines - Migrate theme tokens to Arco, register the Arco theme, and add hook adapter composables (useMessage / useDialog / useNotification) with matching signatures - Sample pages: LoginView and AppSidebar on the new baseline; docs/arco-mapping.md and docs/ui-baseline.md land - agent-bridge: prefer the PM-selected venv from facts.json over legacy in-tree venvs (legacy lacks the mcp extra, so every MCP server showed 0 tools / not connected) - agent-bridge python (vendored, deliberate deviation): MCP discovery import fallback and pyyaml -> hermes_yaml so plugins and MCP work under the PM env; install the mcp extra via `hermes pm install --extra mcp` - Chat-chain fragment: docs/chat-chain-changes/2026-10-17-phase005-arkscope-baseline.md Verified: harness:check, test (2020 passed), test:e2e (30 passed), build all green; manual: plugins 100/0 warnings, MCP 6/6 servers connected with 104 tools.
11 KiB
Phase 005 — ArkScope vendor + 样板页(风格基线)
| 项 | 值 |
|---|---|
| 目标 | vendor 2 个 ArkScope 组件;用 LoginView + AppSidebar 定视觉语言基线 |
| 前置 | Phase 004 通过(项目功能完整) |
| 产出 | docs/ui-baseline.md 定稿;后续批量迁移照它执行 |
| 参考 | docs/03-施工蓝图.md §7 |
0. 为什么必须先做样板页
naive-ui 渗透面是 100 个文件 / 105 处(不只 27 个视图,还含 components/ stores/ composables/)。
先定基线再批量,否则 100 个文件会被改两遍。
1. 功能任务 1 — vendor ArkScope
1.1 上游现状(已核实)
github.com/triplepiers/ArkScope — "对鹰角 UI 组件的拙劣复现",Vue 3 + Vite,无 LICENSE,仓库 322MB。
src/components/ 下的组件绝大多数强绑定游戏美术素材(干员立绘、Banner)。public/assets/ 有 131 个路径全是游戏资源。
只有 2 个组件可脱离素材复用:
| 组件 | 依赖 | 判定 |
|---|---|---|
ScrambleTitle |
纯 DOM + CSS,文字解码动画 | ✅ vendor |
IsometricWave |
CSS filter + 位移,类亚克力 hover | ✅ vendor |
Particle2D / Particle3D |
3D 模型 + 遮罩图 | ❌ 太重 |
OperatorCarousel / ArknightsMedia / GameplayAlbum / NoticeCarousel / FullScreenNavigator / NewsList / EndfieldSidebar / Endfield/* |
全部依赖游戏素材,脱离素材无意义 | ❌ 不 vendor |
其余组件的价值是视觉手法(斜切遮罩、噪点、扫描线、Reveal & Blink),后续页面按需自己实现,不搬代码。
1.2 做法
不作为 npm 依赖,不 clone 整仓。
- 定位上游 commit(
main分支,记录pushed_at),记下来 - 只下载
ScrambleTitle与IsometricWave两个组件目录 - 放到
packages/client/src/vendor/arkscore/<ComponentName>/ - 剥离:
useAssetPreloader/particle3DModels/data/componentRegistry.js/router/views/showcases(上游 demo 工程的东西) - 不搬:
src/assets/**、public/**、上游全局src/style.css(只取组件 scoped 样式) - 保留原文件头注释 + 上游 commit hash
1.3 PROVENANCE.md(必写)
packages/client/src/vendor/arkscore/PROVENANCE.md:
# ArkScope vendored components
- 上游:https://github.com/triplepiers/ArkScope
- commit:<hash>
- 拉取日期:<date>
- vendor 的组件:ScrambleTitle、IsometricWave
- 剥离内容:demo 工程(router/views/showcases/componentRegistry)、assets、public
## 许可证
上游仓库无 LICENSE 文件。
本 vendor 仅用于个人自用,不分发、不商用。
若要公开分发,必须先向上游作者取得授权或替换为自研实现。
## 未 vendor 的组件
其余组件强依赖鹰角游戏美术素材,脱离素材无实际价值,故未 vendor。
本项目仅参考其视觉手法(斜切遮罩、噪点、扫描线等),自行实现。
1.4 新增机械化测试
tests/client/arkscope-vendor.test.ts:
- 断言
vendor/arkscore/下无.png/.jpg/.webp/.mp3/.mp4 - 断言源码内无
src/assets/public/assets引用 - 断言
PROVENANCE.md存在且含 commit hash - 断言组件总数 ≤ 3(防回流)
2. 功能任务 2 — 使用边界(硬约束,写进 AGENTS.md)
| 允许 | 禁止 |
|---|---|
| 登录页标题区装饰位面 | 聊天页(消息区 / 输入区 / 侧边栏) |
| Journey 图谱的背景层 | 任何表单页(Skills / Profiles / Settings / Models) |
| 首屏 loading / 空状态 | 任何表格页(Usage / Logs / Jobs / Kanban) |
| 任何点击交互密集区域 |
判定标准:装饰位面不得承载信息、不得承载交互、不得影响可读性。
pointer-events: none 是硬要求,装饰层绝不能吃掉点击。
3. 功能任务 3 — 主题令牌迁移
3.1 新建 packages/client/src/styles/arco-theme.ts
替换 styles/theme.ts(Naive 的 GlobalThemeOverrides):
export const arcoTheme = {
// 延续旧版克制灰阶
colorPrimary: '#2f2f2f',
colorBgLayout: '#fafafa',
colorBgContainer: '#ffffff',
borderRadius: 6,
fontFamily: 'Inter, system-ui, -apple-system, sans-serif',
fontFamilyMono: '"JetBrains Mono", "Fira Code", monospace',
}
暗色模式走 CSS 变量覆盖,不用 Arco 的 dark theme + overrides 双轨。
3.2 改 App.vue
旧版是 naiveTheme computed(浅/深两套对象)。改为:
<div class="app-root" :class="{ 'dark': isDark }">
暗色由 body[arco-theme='dark'] 承载(Arco 官方机制),app 只负责切换属性。
3.3 改 index.html 的 FOUC 脚本
保留旧版机制(内联脚本读 localStorage 提前定 class),但改为切 arco-theme 属性:
<script>
// 首屏前定主题,避免闪烁
const t = localStorage.getItem('hermes_style')
document.documentElement.setAttribute('arco-theme', t === 'dark' ? 'dark' : 'light')
</script>
localStorage key
hermes_style保留(Phase 002 白名单)。
3.4 styles/variables.scss
保留,但把 Naive 相关的 SCSS 变量映射到 Arco CSS 变量名。Phase 007 会重写 style-system.test.ts。
4. 功能任务 4 — 全局 Provider
main.ts:
import ArcoVue from '@arco-design/web-vue'
import '@arco-design/web-vue/dist/arco.css'
app.use(ArcoVue)
全量注册,不做按需 tree-shaking —— 换迁移速度,包体问题后期再优化。
5. 功能任务 5 — 三个全局 hook 适配层(Phase 006/007 强依赖,先写)
Naive 是 hook API,Arco 是命令式。全仓 200+ 处调用,必须先建适配层并冻结接口,后续批次只调用适配层。
新建 packages/client/src/composables/:
5.1 useMessage.ts
// 模块级单例,main.ts 里 app.use 时把 Message 实例挂上来
export function useMessage() {
return {
success: (c) => Message.success(c),
error: (c) => Message.error(c),
warning: (c) => Message.warning(c),
info: (c) => Message.info(c),
loading: (c) => Message.loading(c),
}
}
5.2 useDialog.ts
export function useDialog() {
return { confirm, info, success, error, warning }
}
5.3 useNotification.ts
export function useNotification() {
return { success, error, warning, info }
}
要求:这三个文件的对外签名定下后不再改。后续所有批次只能调它们。若发现签名不够用,先扩适配层,不要在页面里直接引 Arco 的 Message。
6. 功能任务 6 — 组件映射表
新建 docs/arco-mapping.md,把全仓用到的 Naive 组件逐个映射。先建表再改代码。
已核实的核心映射(完整表在 Phase 006 补全):
| Naive | Arco | 备注 |
|---|---|---|
NConfigProvider |
直接用 body[arco-theme] |
不需要组件 |
NMessageProvider / useMessage |
useMessage() composable |
§5.1 |
NDialogProvider / useDialog |
useDialog() composable |
§5.2 |
NNotificationProvider / useNotification |
useNotification() composable |
§5.3 |
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 无对应,改 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 |
结构差异大 |
生成实际用到的组件清单:
grep -rho "from 'naive-ui'" packages/client/src | wc -l # 105 处
grep -rhoE "N[A-Z][a-zA-Z]+" packages/client/src --include="*.vue" | sort -u
7. 功能任务 7 — 样板页 A:LoginView
选它的理由:只用到输入框 + 按钮 + 少量文本,是最小可控面,且是装饰位面的合法落点。
改造点:
NInput→a-inputNButton→a-button- 标题区挂 ArkScope
ScrambleTitle - 明暗切换走 §3.2 机制
- 装饰层
pointer-events: none - 保留「hermes CLI 缺失引导」的入口(Phase 004 做的
HermesMissingView)
8. 功能任务 8 — 样板页 B:AppSidebar
选它的理由:全站导航唯一入口。Arco 的 Menu / Layout.Sider 语义在这里定型后,其余 20+ 视图的导航写法全部照抄。
改造点:
NLayout/NLayoutSider→a-layout/a-layout-siderNMenu→a-menuNIcon→ Arco IconNSelect(profile 切换)→a-selectNAvatar→a-avatarNTooltip→a-tooltip
它同时是最难场景:深层文件 + v-if="isSuperAdmin" 条件渲染 + 大量 naive 引用。过了这关,剩下的是体力活。
9. 功能任务 9 — 定稿 docs/ui-baseline.md
本 Phase 的核心交付物。必须写清:
- 色板(浅色 / 深色两套,含强调色)
- 圆角 / 间距 / 字号阶梯
- 字体栈(中英 / 等宽)
- 阴影 / 分割线
- 组件使用约定(什么时候用 Modal 什么时候用 Drawer、表格空态怎么处理、loading 怎么做)
- 装饰位面的边界(复述 §2,落到本文档)
- 三条不可破的规则:
- 不引入第三个 UI 库
- 消息气泡内部不用 Arco 组件(性能,见 Phase 006)
- 装饰层一律
pointer-events: none
10. 验收
cd /Users/jack/source/MyProject/js/hermes-ui
# vendor 边界
find packages/client/src/vendor/arkscore -type f \
\( -name "*.png" -o -name "*.jpg" -o -name "*.webp" -o -name "*.mp3" \)
# 期望:零命中
npm run test # 含 arkscope-vendor.test.ts
npm run build
手工
- 登录页渲染正常,ArkScope 位面出现且鼠标穿透
- 明暗切换无闪烁(刷新页面验证)
- 侧边栏菜单全部可点进各视图(视图本身还没迁移,样式不完美是正常的)
npm run dev无 console 报错docs/ui-baseline.md已写完
11. 风险
| # | 风险 | 缓解 |
|---|---|---|
| P5-1 | ArkScope 上游无 LICENSE | 只 vendor 2 个无素材组件;PROVENANCE.md 标注;仅自用;arkscope-vendor.test.ts 卡住素材回流 |
| P5-2 | 装饰层吃掉点击导致登录按钮点不动 | pointer-events: none 写进基线文档 + 手工点一遍 |
| P5-3 | 暗色切换闪烁 | FOUC 脚本在 index.html 内联,必须同步改(§3.3) |
| P5-4 | composable 适配层签名后续不够用 | §5 要求先定后冻结,不够用先扩适配层 |
| P5-5 | 样板页看着好,批量时发现约定不够 | §9 的基线文档要覆盖到 Phase 006/007 会遇到的场景 |
| P5-6 | 忘删 Naive Provider 包裹层 | 改完 grep NConfigProvider / NMessageProvider 确认归零 |
12. 完成标志
风格基线定稿。 进入 Phase 006(聊天页迁移)。