Hermes Agent Wiki 非公式・日本語wiki
この skill をそのまま使う: GitHub で原文を見る

英語原文・frontmatter 込みで、Hermes が読み込む実体そのままです(このページの本文は日本語版)。

Inspecting Hermes Desktop Dom

目次

動いている Hermes デスクトップの DOM/CSS を CDP で読みます。

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 デスクトップの DOM を調べる

概要

apps/desktop を開発していて、利用者が同じアプリ(hgui / npm run dev)を動かしているときは、その人が見ている画面の実際に描画された DOM を読めます。計算後のスタイル、位置と大きさ、どの CSS ルールが実際に勝ったか、 コンソールの出力まで分かるので、.tsx から推測して外すことがなくなります。

開発サーバーで起動した場合、Chrome DevTools Protocol のポートが 127.0.0.1:9222 に自動で開きます。描画側は Chromium のページなので、DevTools で読めるものは スクリプトからも読めます。

これは実際に目で見ることの代わりにはなりません。 CDP が答えられるのは*事実*の問い (「計算後の padding はいくつか」「この要素は描画されたか」「どのセレクタが当たっているか」) です。結果の見栄えが良いかどうかは判断できません。色の釣り合い、余白の感じ、 「これは見苦しいか」は、やはり利用者の目かスクリーンショットが必要です。事実は CDP で答え、美しさの判断は利用者に委ねてください。

こんなときに使います

  • UI の変更が、動いているアプリに本当に反映されたか確かめたいとき
  • 「なぜこの要素はまだ X のままなのか」— 何かを直す前に、勝っているルールを突き止めたいとき
  • これから変更するコンポーネントの、安定したセレクタを探したいとき
  • デザイントークンの計算後の値を、実際のノードで確かめたいとき
  • 利用者が言っているのに書き写せない、描画側のコンソールエラーを読みたいとき

使わない場面: 性能の計測やヒープの調査(node-inspect-debuggerdebugging-hermes-desktop)、そして本当の問いが「これは見た目として正しいか」である場合。

ポート

開発サーバーで起動すると 127.0.0.1:9222 に開きます。閉じるのはちょうど2つの場合だけです (apps/desktop/electron/dev-cdp.ts)。

  • パッケージ済みのビルド — 常に閉じており、環境変数でも上書きできません。
  • HERMES_DESKTOP_DEV_SERVER がない場合 — パッケージ化していない electron .

dist/ に対して動かすのは、パッケージ済みアプリの動作確認のやり方なので、同じ扱いになります。

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 が付いています。


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.mjsSELECTORS に、安定した data-slot の取っかかりがまとまっています (composer、スレッドの表示領域、アシスタントのメッセージ、やり取りの組、プロフィールの帯)。 自分で 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/typographyprose a { font-weight: 500 })は、ユーティリティクラスに 普通に勝ちます。使うたびに上書きするのではなく、共通のクラス側で上書きしてください。

自分専用の隔離したインスタンス

ポートが開いていないとき、あるいは利用者の画面を邪魔できないときに使います。

cd apps/desktop
HERMES_HOME=/tmp/cdp-probe-home \
HERMES_DESKTOP_DEV_SERVER=http://127.0.0.1:5174 \
HERMES_DESKTOP_CDP_PORT=9333 \
  npx electron . --user-data-dir=/tmp/cdp-probe-userdata

--user-data-dir を分けると Electron の単一インスタンスのロックを避けられるので、動いている hgui とぶつかりません。HERMES_HOME を分けることで、本物のセッションからも離せます。 同じ理由で、ポートも 9222 以外を選んでください。バックグラウンドで動かし、終わったら止めます。

性能計測の仕組みも一緒に使いたい場合は、npm run perf:serve が一時的な HERMES_HOME を 組み込んだ同じことをしてくれます。

落とし穴

  • 何かを「空ける」ために、利用者の開発サーバーやアプリを止めては決していけません。 配信の途中で

止めると Chromium のソケットの管理が壊れ、そこで出た ERR_NETWORK_CHANGED が、 直前に変更した箇所のせいにされます。

  • 使い捨ての HERMES_HOME にはバックエンドがありません。 アプリは hermes:api について

ECONNREFUSED をログに出し、自分で終了することもあります。それでも描画側は立ち上がり、DOM は 読めます。早めに読み、自分で終了しただけの調査用インスタンスを、ポートの不具合と取り違えないで ください。Chromium はポートを確保したとき DevTools listening on ws://127.0.0.1:<port>/… と ログに出します。この行が、ポートが開いた証拠です。

  • 1回だけ試すのではなく、繰り返し確認してください。 起動直後のアプリは、ポートが応答するまでに

1〜2秒かかります。

  • DOM 全体を出力しては決していけません。 デスクトップは何百ものノードを描画するので、

outerHTML はコンテキストを埋め尽くします。評価する式の中で、小さな JSON オブジェクトまで 絞り込んでください。

  • CDP.connect には match を渡してください。 これがないと、メインの画面ではなくペットの

重ね表示、クイック入力の画面、devtools の対象につながることがあります。

  • cdp.eval は値をそのまま返しますが、生の Runtime.evaluate は二重に包みます

.result.result.value)。ラッパーを使ってください。

  • このリポジトリでは vite dev のもとで import.meta.env.DEVtrue です。 そうでないと書いてある

apps/desktop/scripts/profile-typing-lag.md の記述は古いものです。