mcpField
I
inspecting-hermes-desktop-dom

inspecting-hermes-desktop-dom

github.com/nousresearch開発258.1k215 回インストール今日更新
リポジトリ

inspecting-hermes-desktop-dom について

Chrome DevTools Protocolを使い、実行中のHermesデスクトップアプリのDOMを調べる開発用スキルです。ソースコードだけに頼らず、描画要素、計算済みスタイル、位置情報、コンソール出力を確認できます。

主な機能

  1. 01実行中のレンダラーDOMの取得
  2. 02計算済みスタイルと位置情報の確認
  3. 03一致するCSSルールと適用ルールの特定
  4. 04レンダラーのコンソール出力の確認
  5. 05安定したdata-slotセレクターの利用

活用シーン

  1. 01実行中アプリでUI変更を確認
  2. 02スタイルが適用されない原因の調査
  3. 03コンポーネント編集前のセレクター特定
  4. 04報告されたレンダラーエラーの確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/nousresearch/hermes-agent --skill inspecting-hermes-desktop-dom

インストール後、Claude Code で/inspecting-hermes-desktop-domを入力して読み込まれたか確認します。

詳細

Hermes デスクトップのライブ DOM を調べる

概要

apps/desktop を開発していて、ユーザーが同じアプリ(hgui / npm run dev)を実行している場合、ユーザーが見ているウィンドウのレンダリング済みライブ DOMを読み取れます。計算済みスタイル、ジオメトリ、実際に適用された CSS ルール、コンソール出力などを確認できるため、.tsx から推測して間違えることがありません。

開発サーバーを実行すると、127.0.0.1:9222 で Chrome DevTools Protocol のポートが自動的に開きます。レンダラーは Chromium のページなので、DevTools が読み取れるものはすべてスクリプトでも読み取れます。

実際に画面を見ることの代わりにはなりません。 CDP は「計算済みのパディング値は何か」「この要素はレンダリングされたか」「どのセレクターが一致するか」といった事実に関する質問には答えられますが、見た目が良いかどうかは判断できません。色のバランスや余白の感覚、「見た目が悪いかどうか」は、ユーザー自身の目かスクリーンショットで確認する必要があります。事実は CDP で確かめ、美的な判断はユーザーに委ねてください。

使用する場面

  • UI の変更が実行中のアプリに実際に反映されたか確認するとき
  • 「この要素がまだ X なのはなぜ?」というとき — 何かを編集する前に、実際に適用されたルールを見つけます
  • 変更する予定のコンポーネントで、安定したセレクターを特定するとき
  • 実際のノードでデザイントークンの計算値を確認するとき
  • ユーザーが言及しているもののコピーできない、レンダラーのコンソールエラーを読むとき

使用しない場面: パフォーマンスのプロファイリングやヒープの調査(node-inspect-debugger、 debugging-hermes-desktop)、または本当の質問が「見た目は正しいか」という場合。

ポート

開発サーバーの実行時は 127.0.0.1:9222 で開きます。以下の 2 つの場合に限り閉じています(apps/desktop/electron/dev-cdp.ts)。

  • パッケージ化されたビルド — 常に閉じており、環境変数で上書きすることもできません。
  • HERMES_DESKTOP_DEV_SERVER がない場合 — パッケージ化されたアプリのスモークテストには、パッケージ化されていない electron . から dist/ を実行するため、パッケージ化されたアプリと同じ動作になります。

何かをする前に確認してください。

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、thread viewport、assistant message、turn pair、profile rail)が用意されています。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 })は、ユーティリティクラスより優先されることがよくあります。その場合は、使用箇所ごとではなく共有クラスで上書きしてください。

独立した自分用インスタンス

ポートが開いていない場合や、ユーザーのウィンドウに影響を与えてはいけない場合は、次のようにします。

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 があらかじめ設定された同じ環境で起動します。

注意事項

  • 「空きを作る」ために、ユーザーの開発サーバーやアプリを絶対に終了しないでください。 配信中に終了すると、Chromium のソケットプールが破棄され、その結果発生する ERR_NETWORK_CHANGED は、直前に変更した内容が原因だと誤解されます。
  • 使い捨ての HERMES_HOME にはバックエンドがありません。 アプリは hermes:api に対して ECONNREFUSED をログに出力し、自動終了することがあります。レンダラーは引き続きマウントされ、DOM も読み取れます。速やかに読み取り、自動終了したプローブをポートの異常と取り違えないでください。Chromium はポートにバインドすると DevTools listening on ws://127.0.0.1:<port>/… をログに出力します。この行がポートの開通を示す証拠です。
  • 一度だけプローブするのではなく、ポーリングしてください。 起動直後のアプリがポートに応答するまで、1、2 秒かかります。
  • DOM 全体を出力しないでください。 デスクトップアプリでは数百のノードがレンダリングされるため、outerHTML を出力するとコンテキストが埋め尽くされます。評価式の中で小さな JSON オブジェクトに絞り込んでください。
  • CDP.connect に match を渡してください。 渡さないと、メインウィンドウではなく、ペットオーバーレイ、クイックエントリーウィンドウ、または開発者ツールのターゲットに接続することがあります。
  • cdp.eval は値を返しますが、生の Runtime.evaluate は値を二重にネストします (.result.result.value)。ラッパーを使用してください。
  • このリポジトリでは、vite dev の実行中に import.meta.env.DEV は true になります。 apps/desktop/scripts/profile-typing-lag.md にある、そうではないとする記述は古くなっています。

コメント