{/* This page is auto-generated from the skill's SKILL.md by website/scripts/generate-skill-docs.py. Edit the source SKILL.md, not this page. */}
Inspecting Hermes Desktop Dom
经 CDP 读取实时 Hermes 桌面 DOM/CSS。
Skill 元数据
| 来源 | 内置(默认安装) |
| 路径 | skills/software-development/inspecting-hermes-desktop-dom |
| 版本 | 1.0.0 |
| 作者 | Hermes Agent |
| 许可证 | MIT |
| 平台 | linux, macos, windows |
| 标签 | desktop, electron, cdp, dom, ui-verification, self-inspection |
| 相关 skill | node-inspect-debugger、systematic-debugging、dogfood |
参考:完整 SKILL.md
以下是 Hermes 在触发该 skill 时加载的完整 skill 定义。这是 agent 在 skill 激活时所看到的指令内容。
检视实时 Hermes 桌面 DOM
概览
当你在开发 apps/desktop、且用户正运行同一应用(hgui / npm run dev)时,你可以读取他们正看着的窗口的实时渲染 DOM——计算样式、几何、哪条 CSS 规则实际胜出、控制台输出——而不是从 .tsx 推断然后出错。
dev-server 运行会自动在 127.0.0.1:9222 打开一个 Chrome DevTools Protocol 端口。渲染器是 Chromium 页面,因此 DevTools 能读的一切,脚本都能读。
这不替代亲眼查看。 CDP 回答事实性问题("计算 padding 是多少"、"这个元素渲染了吗"、"哪个选择器匹配")。它不能告诉你结果好不好看。色彩平衡、间距手感、"这丑不丑"仍需用户的眼睛或截图。用 CDP 回答事实;把美学交给用户。
何时使用
- 验证 UI 变更在运行中的应用里确实生效
- "为什么这个元素还是 X?"——在改任何东西前找出胜出规则
- 为你即将改的组件定位稳定选择器
- 在真实节点上检查设计 token 的计算值
- 读用户提到但复制不出来的渲染器控制台错误
不要用于: 性能 profiling 或堆工作(node-inspect-debugger、debugging-hermes-desktop),或真实问题是"这看着对不对"的任何事。
端口
任何 dev-server 运行都在 127.0.0.1:9222 打开。恰好两种情况关闭(apps/desktop/electron/dev-cdp.ts):
- 打包构建——总是关闭,无环境值可覆盖;
- 无
HERMES_DESKTOP_DEV_SERVER——针对dist/的未打包electron .是冒烟测试打包应用的方式,因此它表现得像打包应用。
HERMES_DESKTOP_CDP_PORT 移动端口(=9333)或禁用它(=off)。
做其他事之前先检查:
curl -s --max-time 3 http://127.0.0.1:${HERMES_DESKTOP_CDP_PORT:-9222}/json/version
空 → 无端口。不要静默猜测另一个端口。
绝不要为拿端口而重启用户的应用。 那会摧毁他们的会话和状态。改为启动你自己的隔离实例(见下)。
读 DOM
apps/desktop/scripts/eval.mjs 是一行命令:
cd apps/desktop
node scripts/eval.mjs "document.querySelectorAll('[data-slot]').length"
多步工作用共享客户端——它有目标发现和 promise 感知的 eval:
import { CDP, SELECTORS } from './scripts/perf/lib/cdp.mjs'
const cdp = await CDP.connect({ port: 9222, match: '5174' })
const out = await cdp.eval(`JSON.stringify({
radius: getComputedStyle(document.documentElement).getPropertyValue('--radius-scalar').trim(),
composer: !!document.querySelector('[data-slot="composer-rich-input"]')
})`)
cdp.close()
scripts/perf/lib/cdp.mjs 中的 SELECTORS 持有稳定 data-slot 钩子(composer、线程视口、助手消息、轮次对、profile 侧栏)。优先用它们,而非自造 querySelector——组件移动时它们作为整体更新。
它最擅长的问题:哪条规则赢了?
因为样式"没生效"而编辑每个调用点是典型浪费。先读真实节点:
const el = document.querySelector('[data-slot="aui_assistant-message-root"] a')
JSON.stringify({
ownClasses: el.className,
weight: getComputedStyle(el).fontWeight,
parents: (() => {
const out = []
let n = el
while ((n = n.parentElement) && out.length < 6) out.push(n.className)
return out
})()
})
若节点自身不带类,该值是继承的——横扫调用点修不好它,你需要祖先规则。插件样式表(如 @tailwindcss/typography 的 prose a { font-weight: 500 }) routinely 压过工具类;在共享类上覆盖,而非每处用法。
你自己的隔离实例
当无端口、或你不得打扰用户窗口时:
cd apps/desktop
HERMES_HOME=$HOME/.hermes/cache/scratch/cdp-probe-home \
HERMES_DESKTOP_DEV_SERVER=http://127.0.0.1:5174 \
HERMES_DESKTOP_CDP_PORT=9333 \
npx electron . --user-data-dir=$HOME/.hermes/cache/scratch/cdp-probe-userdata
单独的 --user-data-dir 避开 Electron 单实例锁,因此不会与运行中的 hgui 冲突;单独的 HERMES_HOME 让它远离真实会话。同理选 9222 以外端口。后台运行,用完杀掉。
npm run perf:serve 内建临时 HERMES_HOME 做同样的事,若你还想要 perf harness。
常见陷阱
- 绝不要为"释放"任何东西而杀掉用户的 dev server 或应用。 服务中途杀掉会炸毁 Chromium 的 socket 池,导致的
ERR_NETWORK_CHANGED会被怪到你刚改的东西上。 - 一次性
HERMES_HOME没有后端。 应用会为hermes:api记ECONNREFUSED并可能自行退出。渲染器仍挂载、DOM 仍可读——及时读,别把自退的探针误认为坏端口。Chromium 绑定时记DevTools listening on ws://127.0.0.1:<port>/…;那行就是端口打开的证明。 - 轮询,而非探一次。 刚启动的应用需要一两秒端口才应答。
- 绝不要 dump 整个 DOM。 桌面渲染数百节点,
outerHTML会淹没你的上下文。在求值表达式内投影成小 JSON 对象。 - 给
CDP.connect传match。 不传,你可能附到宠物浮层、快捷输入窗或 devtools 目标,而非主窗口。 cdp.eval返回值;裸Runtime.evaluate会双层嵌套(.result.result.value)。用包装器。- 本仓库
vite dev下import.meta.env.DEV为true。apps/desktop/scripts/profile-typing-lag.md中相反说法已过时。