用户:「鸿蒙也同步,但是鸿蒙要求用系统方案」。
已转给 dsh(线索 harmony-ui-alignment),并写进计划文档:
- **含义**:能交给系统的就交给系统 —— 用 ArkUI 的组件/材质/语义资源,
而不是把 WebUI 那套"手写 rgba + 自定义模糊 + 自制卡片"照搬。
系统材质会跟随深色模式、动效曲线与无障碍设置,手写的不会。
- **对应表**:`backgroundBlurStyle(BlurStyle.*)` 取代手写模糊;系统 `Tabs`/`TabBar`
取代自制导航条;`List`/`ListItem` 取代 `Scroll`+`Column`;组件自身的
`borderRadius`/`shadow` 取代 `.glass-card`;`$r('sys.color.*')` 语义色取代自切变量
(**顺带解决 WebUI 那个"半深不浅"的病根**);`animateTo`/`transition` 取代自定义动画。
- **对既有判据的影响(重要)**:`cross-client-theme.test.mjs` 钉的是三个**取值**。
改用系统资源后它应当变红 —— 那是预期的,届时要把它从"取值相同"改成"意图相同"
(品牌蓝仍须一致,材质与圆角允许各自跟随系统)。**必须两侧一起改**,
避免一边改了一半。
同时提醒 dsh 两条已同步的语义:列表项与顶部都是"每项一张卡/气泡"(不是通栏);
玻璃只出现在一层。
27 KiB
鸿蒙客户端与 WebUI 的对齐计划
用户(2026-09-14):「安排对齐」「鸿蒙 ui 应当交给对这一块更熟悉的 dsh 负责」。 这份文档把差距与分期写清楚,免得每轮都从"感觉还差什么"重新猜。
负责人:dsh(2026-09-14 起由 jianf 指定)。移交信: 线索
harmony-ui-alignment(dsh@/home/program/agentmail), 信里交代了状态、判据纪律与踩过的坑(判据要点"用户真正会点的那一层"、 不许新写死颜色、不要给单个面单独做深色、模糊只由壁纸层负责、 列表项每项一张卡、ArkTS 编译坑、视觉不可验要如实标注)。我(pi)保留 WebUI/Electron 侧:需要两边一起加令牌之类的配合,回信给 pi。
一、现在的差距(有据可查)
| 能力 | WebUI | 鸿蒙 | 差距性质 |
|---|---|---|---|
| 收件箱 | ✅ | ✅ | — |
| 会话 | ✅(通信页签) | ✅(独立 tab) | 交互不同 |
| 联系人 | ✅ | ✅ | — |
| 发件箱 | ✅(通信页签) | ❌ | 缺页面(数据现成) |
| 授权(权限决策) | ✅(通信页签 + 详情内决策) | ❌ | 缺页面(API 现成) |
| 日历 | ✅ | ❌ | 缺页面(最大一块) |
| 管理(用户管理) | ✅(我的页底部,管理员可见) | ❌ | 缺页面 + 权限判定 |
| 写信 | ✅ 共用 Composer | ✅ 独立实现 | 组件未统一 |
| 底部/侧边导航 | ✅ 悬浮玻璃条 | ⚠️ 系统 TabBar | 观感不同 |
| 主题 / 壁纸(账号级) | ✅ 服务端同步 | ❌ | 未接 |
| 设计令牌 | ✅ :root |
✅ Theme.ets |
已对齐(判据钉住) |
二、已经做完的(本轮之前)
- 设计令牌共用:
common/Theme.ets与 WebUI 的:root一一对应 (品牌蓝、圆角 14/8、导航玻璃 0.72、语义色、字号),并由client/electron/test/cross-client-theme.test.mjs钉住取值一致性。 - 旧调色板清除:页面里的
#1A73E8(Google 蓝)/#333333/#F5F7FA等 与 WebUI 不同的写死色值,全部换成令牌(203 处)。 - 修掉只剩第一个 tab 高亮的 bug(
currentIndex === 0写死)。
二·五、做法上的一条硬要求:用系统方案
用户(2026-09-14):「鸿蒙也同步,但是鸿蒙要求用系统方案」。
含义:能交给系统的就交给系统 —— 用 ArkUI 的组件、材质与语义资源, 而不是把 WebUI 那套"手写 rgba + 自定义模糊 + 自制卡片"照搬过来。 系统材质会跟随深色模式、动效曲线与无障碍设置,手写的那套不会。
| WebUI 做法 | 鸿蒙应该用 |
|---|---|
手写 rgba(...) + backdrop-filter |
backgroundBlurStyle(BlurStyle.*)(系统材质) |
| 自制圆角导航条 | 系统 Tabs + TabBar(barBackgroundBlurStyle) |
自制 Scroll + Column |
系统 List / ListItem(divider / swipeAction) |
.glass-card 手写边框阴影 |
.borderRadius() + .backgroundBlurStyle() + .shadow() |
| 自己切 CSS 变量做深色 | 系统语义色 $r('sys.color.*') 自动跟随 |
| 自定义 transition | animateTo / transition / geometryTransition |
⚠ 影响既有判据:cross-client-theme.test.mjs 目前钉的是三个取值
(品牌蓝 / 圆角 14 / 导航玻璃 0.72)。改用系统资源后它应当变红 ——
那是预期的,届时要把它从"取值相同"改成"意图相同"(品牌蓝仍须一致;
材质与圆角允许各自跟随系统)。改判据需 WebUI 侧(pi)一起改。
三、分期(按"能独立验收"切)
P1 设计语言(pi 已完成) —— 令牌 + 颜色替换 + 编译通过。以下 P2–P6 归 dsh。
P2 发件箱:复用现有列表组件,接口 /mail/sent。验收:能看到已发邮件、
点开进详情;空态有说明。为什么先做它:与收件箱同构,风险最低。
P3 授权页:导航加一项「授权」(or 通信页内页签,见 5.2③),待决列表走
GET /permission/pending,决策走 POST /permission/decide
(body {mail_id, decision, note});详情内也支持决策。
(接口名已于 2026-09-14 由 dsh 核对修正,原写的 /permission/{id}/decide 不存在。)
验收:待决列表与 WebUI 同口径(未决 = 无 permission_result);
点同意/拒绝后状态立刻变;拒绝时可填备注(备注必须随决策送达模型 ——
WebUI 侧踩过这个坑,见 gateway/handler/permission.go 的 Note 传递)。
P4 主题/壁纸同步:接 GET/PUT /me/appearance + 图片走带认证的 fetch。
验收:换账号后外观跟随;服务端"无记录"时以本地为准(不要用默认值覆盖 —— 同 WebUI)。
P5 玻璃悬浮导航:自定义底栏(圆角 + 半透明 + backgroundBlurStyle),
取代系统 TabBar。注意:视觉验收需要设备或签名 HAP,
本机 hdc list targets 为空 ⇒ 只能保证编译与结构,观感要人眼确认。
P6 日历:网格 + 事件读写 + 左右滑动翻页(复用 WebUI 的手势阈值: 水平 ≥40px、≥1.5× 垂直、<600ms)。这一块最大,单独排。
四、验收纪律(照 WebUI 那套)
- 每个页面都要有点它的判据(WebUI 侧就是因为只验结构没验点击, 漏掉了"侧栏点了不翻页")。
- 判据不许只看截图:要量几何/对比度/命中区。
- 无法验证的要如实标注(例如"编译通过、视觉未验"),不能写成"已完成"。
五、交接核对(dsh,2026-09-14 收到 pi 的移交信后)
核对方式:跑构建、跑判据、读代码,不靠转述。
5.1 移交信里属实的两条
hvigorw assembleHap --no-daemonBUILD SUCCESSFUL(改前改后各跑一次)。node --test client/electron/test/cross-client-theme.test.mjs6 条全绿。
5.2 三处纠正(照原计划直接做会踩空)
① P3 的接口名写错了。 计划里写「决策走 POST /permission/{id}/decide」,
实际是 POST /api/v1/permission/decide,body {mail_id, decision, note}
(server/internal/handler/permission.go:301)。而且待决列表不要从收件箱里
筛 permission_*:WebUI 用的是 GET /api/v1/permission/pending
(client/electron/src/api/client.ts:623),鸿蒙照这个走才同口径。
理由不只是"更省事":/me/mail/inbox 默认只取 50 封,而一个会话能连着产生
十几封权限邮件,从收件箱筛会把别的信挤出视野(WebUI 的 mailGroups.ts
开头就是为这件事写的)。用 pending 接口,与 WebUI 同源。
②"不许写死颜色"的判据原来只挡得住列出来的那 8 个旧色值。
判据全绿的同时,pages/ 里还留着 14 处另一套写死的色 —— Google/Material
调色板:#E8F0FE、#E8F5E9、#FFF3E0、#D93025、#777777×2、
#555555、#444444、#cccccc、#aaaaaa、遮罩 #80000000×2、
透明 #00000000×2。枚举挡不住漂移,只有"类"能挡,已改成:
pages/下一个裸色值都不许有(#RRGGBB/#AARRGGBB都算),颜色只能来自common/Theme.ets;页面清单也改成扫目录(旧版硬编码 7 个文件名, 接下来要加的页面会自动逃出判据)。- 变异测试确认能判红:往
InboxPage.ets塞一个#E8F0FE→ 判据红;撤回 → 绿。 - 顺带把权限档位徽标的配色收进令牌:
Theme.permBg/permFg,与 WebUI 的PermissionChip.tsx同一映射(plan=蓝 / workspace=绿 / full=琥珀)。 原先是full ? 绿 : 橙(Material 色),与 WebUI 反着来。 - 判据从 6 条加到 7 条(新增"两边权限档位配色一致",直接拿 WebUI
:root的--c-blue-*/green-*/amber-*比鸿蒙令牌,防"看起来差不多")。
③ 导航的差距不止"观感不同",是信息架构不同。 WebUI(2026-09-14 用户 「导航项就只剩通信,日历,联系人」)已是:**通信(收件箱/发件箱/授权,内部页签
- 未读红/待决策橙徽标)/ 日历 / 联系人**,底部另有"我的(含管理)+ 主题 + 退出", 新建是通信页内悬浮圆形加号;鸿蒙还是 收件箱 / 会话 / 联系人 三个平级 tab, 没有发件、授权、日历,而「会话」在 WebUI 里没有对应入口(WebUI 是按会话把 收件箱分组,没有独立会话页)。 ⇒ P2/P3 不是"再加两个页面",得先对齐信息架构,否则加完还是两套导航。
5.3 一条与鸿蒙无关、但该让 pi 知道的
WebUI 侧 npm test 在 HEAD 上就是红的(test/background.test.mjs):
浅色与深色两套令牌都定义了(自动反色)—— 期望--nav-bg有浅/深两套, 但深色那套已在faacd3c(修"导航栏还是黑色")里被有意去掉, 现在index.css只剩--nav-bg: 255 255 255 / 0.72。导航在壁纸模式下仍参与模糊—— 期望html[data-bg='on'] .nav-rail里有backdrop-filter: blur(,而该规则现在是空的("模糊由壁纸层负责,这里不叠", 见index.css:892)。
两条判据编码的都是已被有意回滚的设计,判据没跟着改。红成了常态, 判据也就不再是判据 —— 这条纪律问题比色值本身更值得先修。
5.4 修订后的分期与"点它"判据
| 期 | 内容 | 判据(必须点到用户会点的那一层) |
|---|---|---|
| P1.5 ✅ | 裸色值清零 + 判据按类挡 + 权限档位配色统一 | 判据 7/7 绿 + 变异能判红 + 构建成功 |
| P2a | 信息架构:「通信」一项,内部页签 收件箱/发件箱/授权(未读红、待决策橙徽标) | 点页签 → 断言落到哪个 pane(不是断言页签个数);点「通信」回到上次的子页签 |
| P2b | 发件箱页:GET /me/mail/sent,复用列表项 |
能看到已发邮件、点开进详情、空态有说明 |
| P3 | 授权页:GET /permission/pending + POST /permission/decide |
未决口径与 WebUI 一致(无 permission_result);点同意/拒绝后状态立刻变;拒绝可填备注且备注送达模型;决策请求已过期(expired)必须当场说清"这次批准不会恢复原调用" |
| P4 | 主题/壁纸(/me/appearance) |
换账号外观跟随;服务端无记录时以本地为准,不用默认值覆盖 |
| P5 | 悬浮玻璃导航(取代系统 TabBar) | 模糊只由壁纸层负责;列表项每项一张卡;命中区 ≥44vp |
| P6 | 日历(/calendar/events,含 ics 导入导出) |
手势阈值与 WebUI 一致(水平 ≥40px、≥1.5× 垂直、<600ms) |
视觉/交互怎么验:本机有 harmony-emu(实例 HarmonyPhone,hdc 在
/opt/harmonyos/ohos-sdk/linux/toolchains),能起来就能截图 + 真点,
把"编译通过、视觉未验"变成"点过、有截图"。
实测(2026-09-14):当前文件沙箱(workspace-write)下起不来 ——
harmony-emu start 卡在等一个永远不来的 hdc(脚本要写 /run/harmony-emulator.pid),
直启 Emulator -start HarmonyPhone -noWindow 则报
Error opening logfile /root/.Huawei/Emulator/deployed/HarmonyPhone/Log/qemu.log: Permission denied
(实例目录在 /root 下,沙箱不许写)。要跑真机/模拟器判据,得先放宽文件权限
(或换有设备的机器);在那之前,鸿蒙侧的判据只能到"构建通过 + 结构/令牌一致",
观感与点击必须如实标注未验 —— 不许写成已完成。
5.5 待定(需要 pi 或用户一句话)
- 「会话」这个平级入口留不留? WebUI 没有它(收件箱按会话分组)。 我倾向跟 WebUI 一致 —— 收件箱按会话折叠、去掉平级「会话」tab; 但这是删入口,改之前要一句话确认。 → 已答(见 5.6):不是删功能,是两个 tab 合成一个页面的两种视图;先补视图与折叠,再删 tab。
- 新增令牌
accentStrong / warnBg / warnFg / overlay取的都是 WebUI 已有的 tailwind 值(blue-700 / amber-50 / amber-700),WebUI 侧不需要动代码;overlay是唯一没有对应物的(WebUI 弹层不压遮罩)。若 pi 认为 WebUI 侧也该 立同名令牌,我再改。 → 已答(见 5.6):WebUI 侧不立同名令牌;鸿蒙侧的overlay拆成overlayColor+overlayAlpha。
六、pi 的回复已落地(dsh,2026-09-14 下午)
6.1 「会话」入口的结论(pi 作为 WebUI 侧负责人)
不是删功能,是两个 tab 合成一个页面的两种视图:联系人页就是会话列表
(ContactPanel.tsx 有列表 / 卡片两个视图 —— ContactRow ≈ 现在的 ContactsTab;
WorkCard「工作列表」≈ 现在的 SessionsTab:主题、最新一封摘要、权限档位徽标、
往返预算 = 现在的 used_rounds/max_rounds),而收件箱里会话是组织方式
(mailGroups.ts 的 groupMailsBySession() 按 session_id 折叠、组头取最新一封,
isFlatGroup() 让单封不成组)。
落地顺序(原样采纳):
- 先给「联系人」页补列表 / 卡片切换,卡片视图承接预算条 /
status/ 对方 Agent; 收件箱加按会话折叠(组头带未读)。折叠前先看total—— 别让"只取了 50 封" 被折叠伪装成"只有这么多会话"。 - 两件都到位后再删平级「会话」tab。在那之前删 = 丢信息:轮次预算、
status、from_agent会无处可看,而"预算跑满"正是需要人介入的信号。
合并后导航正好是 通信 / 日历 / 联系人 三项,P4–P6 都在这个形态上做。 ⇒ 分期顺序调整为:P2a 联系人双视图 + 收件箱按会话折叠 → P2b 通信页签(收件/发件/授权) → P3 授权页 → P4 主题壁纸 → P5 悬浮玻璃导航 → P6 日历 → 最后删「会话」tab。
6.2 遮罩令牌
overlay 拆成 overlayColor + overlayAlpha(WebUI 是 --bg-scrim 色 + --bg-dim
透明度的两段式;色要能随主题换向,焊死成一个 #AARRGGBB 等于把枚举写回代码)。
ArkUI 只认单值,故用 Theme.overlay() 组装。WebUI 侧不立同名令牌(立了没人用、
判据只能验"它存在",那是自证)。判据第 8 条钉住这个形态。
6.3 那两条红判据的 patch:已落地,且验证过能判红
test/background.test.mjs 第 18 组三条按 pi 的 patch 重写:标签改回它真正断言的东西,
两条方向相反的断言取代原两条(.dark 不许单独给导航换色 / 模糊只由壁纸层负责)。
变异验证:
- 往某个
.dark { }里塞一行--nav-bg: 15 23 42 / 0.72;→ 红; - 往
html[data-bg='on'] .nav-rail里塞backdrop-filter: blur(18px);→ 红; - 撤回 → 绿。背景判据 32 → 34 通过。
6.4 顺手发现并修掉的真 bug(构建只在日志里警告的那种)
src/background-takeover.generated.css 的头注释提前闭合:生成器在注释里写了
「src」加「/」加两颗星加「/」加「.tsx」,其中那对「星号 + 斜杠」把 CSS 注释就地结束,
剩下的尾巴变成 CSS 正文、并与第一条规则的选择器连在一起 ⇒ 非法选择器 ⇒
.bg-amber-100 那条接管规则被浏览器整条丢掉(壁纸模式下它不再变半透明)。
构建只给一条 [WARNING] Unexpected "14" [css-syntax-error],不报错、不影响构建。
改在生成器 scripts/gen-background-takeover.mjs(注释里只描述、不写 glob 字面量)并
重新生成:压缩输出现在以 html[data-bg=on] .bg-amber-100{ 起头、14 条规则全在、无告警。
另加两条判据("头注释没提前闭合" + 自检)。
6.5 一条判据从来没被跑过
cross-client-theme.test.mjs 不在 npm test 链里(npm test 只跑
markdown-xss / narrow-layout / theme / background / packaging + vitest,
而 vitest 只收 test/components 与 test/stores)—— 那条"防漂移判据"从没在默认套件
里跑过。已加进 npm test。
6.6 npm test 现在全绿(退出码 0)
窄屏布局全通过、主题 30、背景 34、cross-client 8、packaging 3、vitest 258 用例 / 15 文件全过。
其中 packaging 第 3 条此前是红的,但它不是判据过期,是安装包真的落后于 dist
(release/linux-unpacked/resources/app.asar 里装的还是旧前端)。根因有点讽刺:
npm test 的 && 链一直在 background 那条就中断,packaging 从来没跑到过。
已 npm run build + npx electron-builder --linux -c.electronDownload.isVerifyChecksum=false 重打包。
⚠️ deb 目标在本机打不出来(fpm 的 portable ruby 在 Dir.chdir 处退出),
AppImage 与 linux-unpacked 正常 —— 交付前要确认这个环境问题不影响目标平台。
6.7 WebUI 侧同源残留(pi 指出的第三处,已修)
Sidebar.tsx 底部的主题切换 / 退出登录按钮原为
text-chrome-400 hover:text-white hover:bg-chrome-800、外层分隔线 border-chrome-700
—— 那是"框架本来就该深"的假设。导航改白玻璃后 chrome-400 在白底上约 2.6:1
(图标要 3:1),hover 还会在白导航上闪出一块近黑。已换成 .nav-item + border-gray-200。
未加"Sidebar 里不许有 chrome-*"的判据:Sidebar.tsx 另有一处
bg-chrome-600 text-chrome-100 是实心小色块(正常用法),一刀切会误红。
6.8 仍未验的
鸿蒙侧视觉与点击仍未验(模拟器在本机沙箱下起不来,见 5.4)—— 本轮的鸿蒙改动只有颜色令牌,判据能覆盖;到 P2a 一定要有人眼或设备, 否则"点页签落在哪个 pane"这条判据无法证明。
七、P2a 落地(dsh,2026-09-14 稍晚)
按 pi 给的顺序:先补视图与折叠,再删 tab。本轮做完前一半,tab 保留。
7.1 做法:把"用户真正会点的那一层"的内核抽出来,让判据执行它
没有设备,"点一下"在鸿蒙上暂时无法自动验。应对不是编个能过的新判据,
而是把会点的那一层的内核抽成纯逻辑文件
client/harmony/entry/src/main/ets/model/MailGrouping.ts(无 UI 依赖),
判据用 node 的 --experimental-strip-types 直接跑同一份代码:
client/electron/test/harmony-logic.test.mjs(14 条)—— 断言的是行为: 折叠后组头是不是最新一封、单封是不是不成组、同一时刻是否用mail_id倒序兜底、 时间解析失败会不会让顺序依赖入参、多账号同名会话会不会被错并、预算剩 1 个来回是哪档。- 页面那一层用源码判据钉"确实调了这些函数"(
groupMailsBySession/isFlatGroup/toggleExpanded/budgetLabel/nextContactView/lastFromIsHuman)—— 两层合起来,「逻辑对」与「页面接上了」都有判据。 - 变异验证(4 处,全部判红):去掉组内排序 → 2 条红;预算阈值
<=1改<1→ 1 条红; 分组键去掉账号前缀 → 1 条红;页面不再区分单封组 → 1 条红。
这条判据已接进 npm test(node --experimental-strip-types --no-warnings --test)。
7.2 收件箱:按会话折叠
- 组头取组内最新一封的别名与主题(与 WebUI
mailGroups.ts同口径), 带未读数徽标与「N 封」;点组头展开/收起。 - 单封不成组、平铺(与 WebUI
isFlatGroup同结论):给孤立的一封信套组头 只是多一次点击,而收件箱里大多数人类来信就是孤立的一封。 - 多账号是鸿蒙特有:分组键带账号前缀(同一
session_id出现在两个账号是两件事);session_id缺失时按mail:<id>各自成组。
7.3 顺带修掉一个"看起来是总数、其实是未读数"的显示
/me/mail/inbox 返回的 total 是 CountUnread(未读总数),不是总封数
(server/internal/handler/me.go 的 MeGetInbox)。鸿蒙底部原来写「共 N 封」,
于是同一屏上会出现「共 7 封」和「未读 7」这种自相矛盾的两行字。
改法:未读数改用服务端 total(权威,原来数这一页会少报);
「共 N 封」改成「已加载 N 封」;并且这一页取满(=50)时如实提示
「已加载 50 封(本页上限 50,可能还有更多)」 —— 客户端手上根本没有可信的总封数,
那就不能把 50 封说成全部(这正是 pi 提醒的"别让只取 50 封伪装成只有这么多会话")。
WebUI 侧完全不读这个字段(mailStore 里没有 total),所以这条只影响鸿蒙。
7.4 联系人页:补上卡片视图(为撤 tab 做准备)
- 右上角切换列表 / 卡片,标题随视图变(「联系人」/「工作列表」,与 WebUI 同词);
切换规则在
nextContactView(),判据直接执行它。 - 卡片(对应 WebUI 的
WorkCard):Agent 名 + 工作目录 + 未读徽标、 会话别名(空则「(未命名会话)」)、主题当主角、最新摘要 + 人/Agent 标记 (lastFromIsHuman)、「N 封 · 时间」、权限档位徽标、往返预算条 (档位与 WebUIBudgetChip同一判据:剩 0 红 / 剩 ≤1 橙 / 其余中性;上限 0=不限则不显示)。 - 平级「会话」tab 暂时保留 —— 预算、
status、from_agent现在卡片视图里都能看了, 但按 pi 的顺序,删 tab 排在 P2b 之后、作为独立一步(撤早了会丢信息)。
7.5 本轮验证与如实标注
hvigorw assembleHapBUILD SUCCESSFUL(.ts纯逻辑模块能被.ets引用, 实测可行 —— 这是"判据能执行同一份代码"的前提)。npm test退出码 0:窄屏布局全通过、主题 30、背景 34、cross-client 8、 harmony-logic 14、packaging 3、vitest 258/258。- 视觉与点击仍未验(无设备 / 模拟器起不来):折叠展开的手感、卡片间距、 组头命中区是否够大,这些没有任何自动判据能代替人眼 —— 交付时按"结构/逻辑已验证、 观感未验"写。下一轮:P2b 通信页签(收件箱/发件箱/授权 + 徽标)。
7.6 模拟器为什么仍然起不来:权限门是"无人可批准"
7.5 的"无设备"这次查到根上了。DevEco CLI 的说明(deveco-cli skill)确认本机
有一个按需启动的模拟器实例 HarmonyPhone(KVM,harmony-emu start 即可,
起来后 devecocli ui layout / click / screenshot 能做真正的点击级验证)。
但 harmony-emu start 要把 PID/日志写到 /run 与 /root/.Huawei(工作区之外),
在 workspace-write 沙箱下被拒;按规矩用 sandbox_permissions 升级重试一次,得到的是:
无法执行 bash:权限询问无法送达:该任务链上没有人类用户
也就是说:鸿蒙的点击级验证在这条链上不是"还没做",而是"当前做不到" ——
需要人类在命令行里跑一次 harmony-emu start,之后 devecocli ui 就能自动点。
在那之前,鸿蒙侧任何界面改动的验收口径只能是
「逻辑有可执行判据 + 页面接线有判据 + 观感未验」,不能写"已完成"。
(给上游的可执行请求:在有人的环境里执行
harmony-emu start && cd client/harmony && hvigorw assembleHap && hdc install entry/build/default/outputs/default/entry-default-unsigned.hap,
即可让 P2a 之后所有阶段的"点击级判据"落地。)
7.7 顺手把"判据套件"本身修可信(同一族问题的总账)
这轮撞出来的问题里,有一类是判据自己不会跑,比判据写错更隐蔽(输出看起来一切正常):
cross-client-theme.test.mjs从来不在npm test链里(pi 已认领);- 有人新加的 4 条玻璃判据写在
process.exit()之后 —— 一条都不执行、不计通过也不计失败; nav-merge.test.mjs、build-stamp.test.mjs写好了也没接线(各 8 / 4 条判据从未跑过);npm test是&&链:前面红一条,后面全部不跑(packaging那条因此长期隐身)。
改法(test/run-all.mjs,pi 建议的"全跑完再算退出码"):
- 每条判据都跑,红的收集起来最后一起报、一起退出;
- 自检 1:清单里的文件必须存在(写错名字 = 一条判据静默消失);
- 自检 2:
test/下每个*.test.mjs都必须在清单里 —— 新增判据忘了接线直接红。 这条自检当场就抓出上面第 3 条那两个文件。 - 变异验证:把
theme.test.mjs强制红 → 后面 5 条判据照跑,汇总如实报"红 1/9"、退出码 1。
接线后又立刻暴露出两条陈旧判据(代码没错、判据钉的是旧写法),已按"钉行为不钉字面"修好:
setViewMode(target || commTab→ 代码后来等价改写成target ?? (isComm ? commTab : modes[0]);改成钉"isComm 时落到 commTab"这个行为;MailView.tsx里 grepglass-control→ 授权多选胶囊抽成了共用组件ComposerChip, 样式其实是对的(neutral 未选中态就是glass-control);改成钉 "MailView 用 ComposerChip" + "ComposerChip 用控件档"。两条都做了变异验证(改坏必红)。
按 pi 的提议还给生成产物补了一条判据:用 postcss 真解析 background-takeover.generated.css,
断言每条规则的选择器形状都恰好是 html[data-bg='on'] .bg-xxx 且规则条数与清单一致 ——
把"生成器写坏产物"从"只有浏览器能发现"变成"跑判据就红"。
(注意:只验"能解析"不够 —— 实测 postcss 对当年那份坏产物照样解析出 1 条规则,
只是选择器前面粘上了注释的尾巴;所以卡的是形状与条数。)
套件现状:npm test = node test/run-all.mjs && vitest run,9 个判据文件全绿
(markdown-xss / narrow-layout / nav-merge / theme / background 42 / cross-client 8 /
harmony-logic 14 / build-stamp 4 / packaging 3)+ vitest 258/258。
7.8 deb 那条结论要撤回:不是 fpm,是 /tmp 满了
pi 问的 deb 复测有结果了:TMPDIR=/var/tmp/ebtmp 在本沙箱里建不出来
(工作区外不可写),但把 TMPDIR 指到工作区大盘后 deb 打出来了:
release/agentmail-web_0.1.0_amd64.deb(约 100MB)。
真因不是权限也不再是 fpm:日志里的关键行是 Errno::ENOSPC —— fpm 会把
release/linux-unpacked(291MB)整份复制进 TMPDIR,而本机 /tmp 是 9.8G 的 tmpfs、
被 /tmp/gocache(4.5G)等占到 99%(仅剩 ~100MB 可用)。
所以「本机打不出 deb」这个结论撤回:它是环境症状,不是工具链缺陷,
deb 也不必从 targets 里摘。已写进 client/electron/BUILD.md(含排查命令)。
顺带(给所有 agent 的提醒):本机 /tmp 已 99% 满,hvigor 之类的构建会把它进一步挤爆;
大产物构建请把 TMPDIR 指到工作区所在盘。