Files
toor 4baccd5d88 Phase 005: vendor ArkScope, land the Arco style baseline, and fix bridge interpreter resolution
- 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.
2026-10-17 09:45:30 +08:00

11 KiB
Raw Permalink Blame History

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 整仓。

  1. 定位上游 commit(main 分支,记录 pushed_at),记下来
  2. 只下载 ScrambleTitle 与 IsometricWave 两个组件目录
  3. 放到 packages/client/src/vendor/arkscore/<ComponentName>/
  4. 剥离:useAssetPreloader / particle3DModels / data/componentRegistry.js / router / views / showcases(上游 demo 工程的东西)
  5. 不搬:src/assets/**、public/**、上游全局 src/style.css(只取组件 scoped 样式)
  6. 保留原文件头注释 + 上游 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-input
  • NButton → 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-sider
  • NMenu → a-menu
  • NIcon → Arco Icon
  • NSelect(profile 切换)→ a-select
  • NAvatar → a-avatar
  • NTooltip → a-tooltip

它同时是最难场景:深层文件 + v-if="isSuperAdmin" 条件渲染 + 大量 naive 引用。过了这关,剩下的是体力活。


9. 功能任务 9 — 定稿 docs/ui-baseline.md

本 Phase 的核心交付物。必须写清:

  1. 色板(浅色 / 深色两套,含强调色)
  2. 圆角 / 间距 / 字号阶梯
  3. 字体栈(中英 / 等宽)
  4. 阴影 / 分割线
  5. 组件使用约定(什么时候用 Modal 什么时候用 Drawer、表格空态怎么处理、loading 怎么做)
  6. 装饰位面的边界(复述 §2,落到本文档)
  7. 三条不可破的规则:
    • 不引入第三个 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(聊天页迁移)。