[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6CAQM1NFVMZXTBH7DMJ9KHD":3,"skill-same:01M6CAQM1NFVMZXTBH7DMJ9KHD":78},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":17,"publishedAt":42,"linkOnly":43,"markdownContent":44,"markdownBody":45,"frontMatter":46,"refName":57,"commitSha":58,"skillDirectory":59,"forksCount":60,"repositoryHtmlUrl":61,"repositoryHomepageUrl":6,"ownerHtmlUrl":62,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":63,"install":64,"resources":77},"01M6CAQM1NFVMZXTBH7DMJ9KHD","inspecting-hermes-desktop-dom",null,"Read the live Hermes desktop DOM\u002FCSS over CDP.","jleechanorg\u002Fjleechan-skills","jleechanorg","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F221404966?v=4","01M6C1VJ99XG950X1DWPEBCBGX","01M6C1VJDK5YVDNT3362RT5WSB",6,"MIT","https:\u002F\u002Fgithub.com\u002Fjleechanorg\u002Fjleechan-skills\u002Fblob\u002Fmain\u002Fhermes\u002Fskills\u002Fsoftware-development\u002Finspecting-hermes-desktop-dom\u002FSKILL.md",[],[18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41],"dom","hermes desktop","desktop","hermes","inspecting hermes desktop dom","node","inspection","systematic-debugging","inspect","systematic","self","cdp","dogfood","read","macos","hermes agent","debugger","ui","verification","debugging","windows","electron","linux","css","2026-11-10 10:12:30",false,"---\nname: inspecting-hermes-desktop-dom\ndescription: \"Read the live Hermes desktop DOM\u002FCSS over CDP.\"\nversion: 1.0.0\nauthor: Hermes Agent\nlicense: MIT\nplatforms: [linux, macos, windows]\nmetadata:\n  hermes:\n    tags: [desktop, electron, cdp, dom, ui-verification, self-inspection]\n    related_skills: [node-inspect-debugger, systematic-debugging, dogfood]\n---\n\n# Inspecting the live Hermes desktop DOM\n\n## Overview\n\nWhen you are developing `apps\u002Fdesktop` and the user is running that same app\n(`hgui` \u002F `npm run dev`), you can read the **live rendered DOM** of the window\nthey are looking at — computed styles, geometry, which CSS rule actually won,\nconsole output — instead of inferring it from `.tsx` and being wrong.\n\nDev-server runs open a Chrome DevTools Protocol port on `127.0.0.1:9222`\nautomatically. The renderer is a Chromium page, so everything DevTools can read,\na script can read.\n\n**This does not replace looking at it.** CDP answers *factual* questions (\"what\nis the computed padding\", \"did this element render\", \"which selector matches\").\nIt cannot tell you whether the result looks good. Colour balance, spacing feel,\nand \"is this ugly\" still need the user's eyes or a screenshot. Answer facts with\nCDP; hand aesthetics to the user.\n\n## When to Use\n\n- Verifying a UI change actually took effect in the running app\n- \"Why is this element still X?\" — find the winning rule before editing anything\n- Locating a stable selector for a component you're about to change\n- Checking a design token's computed value on a real node\n- Reading renderer console errors the user mentions but can't copy out\n\n**Don't use for:** perf profiling or heap work (`node-inspect-debugger`,\n`debugging-hermes-desktop`), or anything where the real question is \"does this\nlook right\".\n\n## The port\n\nOpen on `127.0.0.1:9222` for any dev-server run. Closed in exactly two cases\n(`apps\u002Fdesktop\u002Felectron\u002Fdev-cdp.ts`):\n\n- **packaged builds** — always, and no environment value overrides it;\n- **no `HERMES_DESKTOP_DEV_SERVER`** — an unpackaged `electron .` against\n  `dist\u002F` is how the packaged app gets smoke tested, so it behaves like one.\n\n`HERMES_DESKTOP_CDP_PORT` moves the port (`=9333`) or disables it (`=off`).\n\nCheck before doing anything else:\n\n```bash\ncurl -s --max-time 3 http:\u002F\u002F127.0.0.1:${HERMES_DESKTOP_CDP_PORT:-9222}\u002Fjson\u002Fversion\n```\n\nEmpty → no port. Do not guess another port silently.\n\n**Never relaunch the user's app to get a port.** That destroys their session and\ntheir state. Launch your own isolated instance instead (below).\n\n## Reading the DOM\n\n`apps\u002Fdesktop\u002Fscripts\u002Feval.mjs` is the one-liner:\n\n```bash\ncd apps\u002Fdesktop\nnode scripts\u002Feval.mjs \"document.querySelectorAll('[data-slot]').length\"\n```\n\nFor multi-step work use the shared client — it has target discovery and\npromise-aware eval:\n\n```js\nimport { CDP, SELECTORS } from '.\u002Fscripts\u002Fperf\u002Flib\u002Fcdp.mjs'\n\nconst cdp = await CDP.connect({ port: 9222, match: '5174' })\nconst out = await cdp.eval(`JSON.stringify({\n  radius: getComputedStyle(document.documentElement).getPropertyValue('--radius-scalar').trim(),\n  composer: !!document.querySelector('[data-slot=\"composer-rich-input\"]')\n})`)\ncdp.close()\n```\n\n`SELECTORS` in `scripts\u002Fperf\u002Flib\u002Fcdp.mjs` holds the stable `data-slot` hooks\n(composer, thread viewport, assistant message, turn pair, profile rail). Prefer\nthem over inventing a `querySelector` — they are updated as a unit when\ncomponents move.\n\n## The question this is best at: which rule won?\n\nEditing every call site because a style \"isn't applying\" is the classic waste.\nRead the real node first:\n\n```js\nconst el = document.querySelector('[data-slot=\"aui_assistant-message-root\"] a')\nJSON.stringify({\n  ownClasses: el.className,\n  weight: getComputedStyle(el).fontWeight,\n  parents: (() => {\n    const out = []\n    let n = el\n    while ((n = n.parentElement) && out.length \u003C 6) out.push(n.className)\n    return out\n  })()\n})\n```\n\nIf the node carries no class of its own, the value is **inherited** — sweeping\ncall sites will not fix it, and you need the ancestor rule. A plugin stylesheet\n(e.g. `@tailwindcss\u002Ftypography`'s `prose a { font-weight: 500 }`) routinely beats\na utility class; override on the shared class, not at each usage.\n\n## Your own isolated instance\n\nWhen there is no port, or you must not disturb the user's window:\n\n```bash\ncd apps\u002Fdesktop\nHERMES_HOME=\u002Ftmp\u002Fcdp-probe-home \\\nHERMES_DESKTOP_DEV_SERVER=http:\u002F\u002F127.0.0.1:5174 \\\nHERMES_DESKTOP_CDP_PORT=9333 \\\n  npx electron . --user-data-dir=\u002Ftmp\u002Fcdp-probe-userdata\n```\n\nThe separate `--user-data-dir` dodges Electron's single-instance lock, so it\ncannot collide with a running `hgui`; the separate `HERMES_HOME` keeps it away\nfrom real sessions. Pick a port other than 9222 for the same reason. Run it in\nthe background and kill it when done.\n\n`npm run perf:serve` does the same with a temp `HERMES_HOME` baked in, if you\nalso want the perf harness.\n\n## Pitfalls\n\n- **Never kill the user's dev server or app to \"free\" anything.** A mid-serve\n  kill nukes Chromium's socket pool, and the resulting `ERR_NETWORK_CHANGED`\n  gets blamed on whatever you just changed.\n- **A throwaway `HERMES_HOME` has no backend.** The app logs `ECONNREFUSED` for\n  `hermes:api` and may exit on its own. The renderer still mounts and the DOM is\n  readable — read promptly, and don't mistake a self-exited probe for a broken\n  port. Chromium logs `DevTools listening on ws:\u002F\u002F127.0.0.1:\u003Cport>\u002F…` when it\n  binds; that line is the proof the port opened.\n- **Poll, don't probe once.** A just-launched app needs a second or two before\n  the port answers.\n- **Never dump the whole DOM.** The desktop renders hundreds of nodes and\n  `outerHTML` will bury your context. Project down to a small JSON object inside\n  the evaluated expression.\n- **Pass `match` to `CDP.connect`.** Without it you may attach to the pet\n  overlay, quick-entry window, or a devtools target instead of the main window.\n- **`cdp.eval` returns the value; raw `Runtime.evaluate` double-nests it**\n  (`.result.result.value`). Use the wrapper.\n- **`import.meta.env.DEV` is `true` under `vite dev`** in this repo. The note in\n  `apps\u002Fdesktop\u002Fscripts\u002Fprofile-typing-lag.md` claiming otherwise is stale.\n","# Inspecting the live Hermes desktop DOM\n\n## Overview\n\nWhen you are developing `apps\u002Fdesktop` and the user is running that same app\n(`hgui` \u002F `npm run dev`), you can read the **live rendered DOM** of the window\nthey are looking at — computed styles, geometry, which CSS rule actually won,\nconsole output — instead of inferring it from `.tsx` and being wrong.\n\nDev-server runs open a Chrome DevTools Protocol port on `127.0.0.1:9222`\nautomatically. The renderer is a Chromium page, so everything DevTools can read,\na script can read.\n\n**This does not replace looking at it.** CDP answers *factual* questions (\"what\nis the computed padding\", \"did this element render\", \"which selector matches\").\nIt cannot tell you whether the result looks good. Colour balance, spacing feel,\nand \"is this ugly\" still need the user's eyes or a screenshot. Answer facts with\nCDP; hand aesthetics to the user.\n\n## When to Use\n\n- Verifying a UI change actually took effect in the running app\n- \"Why is this element still X?\" — find the winning rule before editing anything\n- Locating a stable selector for a component you're about to change\n- Checking a design token's computed value on a real node\n- Reading renderer console errors the user mentions but can't copy out\n\n**Don't use for:** perf profiling or heap work (`node-inspect-debugger`,\n`debugging-hermes-desktop`), or anything where the real question is \"does this\nlook right\".\n\n## The port\n\nOpen on `127.0.0.1:9222` for any dev-server run. Closed in exactly two cases\n(`apps\u002Fdesktop\u002Felectron\u002Fdev-cdp.ts`):\n\n- **packaged builds** — always, and no environment value overrides it;\n- **no `HERMES_DESKTOP_DEV_SERVER`** — an unpackaged `electron .` against\n  `dist\u002F` is how the packaged app gets smoke tested, so it behaves like one.\n\n`HERMES_DESKTOP_CDP_PORT` moves the port (`=9333`) or disables it (`=off`).\n\nCheck before doing anything else:\n\n```bash\ncurl -s --max-time 3 http:\u002F\u002F127.0.0.1:${HERMES_DESKTOP_CDP_PORT:-9222}\u002Fjson\u002Fversion\n```\n\nEmpty → no port. Do not guess another port silently.\n\n**Never relaunch the user's app to get a port.** That destroys their session and\ntheir state. Launch your own isolated instance instead (below).\n\n## Reading the DOM\n\n`apps\u002Fdesktop\u002Fscripts\u002Feval.mjs` is the one-liner:\n\n```bash\ncd apps\u002Fdesktop\nnode scripts\u002Feval.mjs \"document.querySelectorAll('[data-slot]').length\"\n```\n\nFor multi-step work use the shared client — it has target discovery and\npromise-aware eval:\n\n```js\nimport { CDP, SELECTORS } from '.\u002Fscripts\u002Fperf\u002Flib\u002Fcdp.mjs'\n\nconst cdp = await CDP.connect({ port: 9222, match: '5174' })\nconst out = await cdp.eval(`JSON.stringify({\n  radius: getComputedStyle(document.documentElement).getPropertyValue('--radius-scalar').trim(),\n  composer: !!document.querySelector('[data-slot=\"composer-rich-input\"]')\n})`)\ncdp.close()\n```\n\n`SELECTORS` in `scripts\u002Fperf\u002Flib\u002Fcdp.mjs` holds the stable `data-slot` hooks\n(composer, thread viewport, assistant message, turn pair, profile rail). Prefer\nthem over inventing a `querySelector` — they are updated as a unit when\ncomponents move.\n\n## The question this is best at: which rule won?\n\nEditing every call site because a style \"isn't applying\" is the classic waste.\nRead the real node first:\n\n```js\nconst el = document.querySelector('[data-slot=\"aui_assistant-message-root\"] a')\nJSON.stringify({\n  ownClasses: el.className,\n  weight: getComputedStyle(el).fontWeight,\n  parents: (() => {\n    const out = []\n    let n = el\n    while ((n = n.parentElement) && out.length \u003C 6) out.push(n.className)\n    return out\n  })()\n})\n```\n\nIf the node carries no class of its own, the value is **inherited** — sweeping\ncall sites will not fix it, and you need the ancestor rule. A plugin stylesheet\n(e.g. `@tailwindcss\u002Ftypography`'s `prose a { font-weight: 500 }`) routinely beats\na utility class; override on the shared class, not at each usage.\n\n## Your own isolated instance\n\nWhen there is no port, or you must not disturb the user's window:\n\n```bash\ncd apps\u002Fdesktop\nHERMES_HOME=\u002Ftmp\u002Fcdp-probe-home \\\nHERMES_DESKTOP_DEV_SERVER=http:\u002F\u002F127.0.0.1:5174 \\\nHERMES_DESKTOP_CDP_PORT=9333 \\\n  npx electron . --user-data-dir=\u002Ftmp\u002Fcdp-probe-userdata\n```\n\nThe separate `--user-data-dir` dodges Electron's single-instance lock, so it\ncannot collide with a running `hgui`; the separate `HERMES_HOME` keeps it away\nfrom real sessions. Pick a port other than 9222 for the same reason. Run it in\nthe background and kill it when done.\n\n`npm run perf:serve` does the same with a temp `HERMES_HOME` baked in, if you\nalso want the perf harness.\n\n## Pitfalls\n\n- **Never kill the user's dev server or app to \"free\" anything.** A mid-serve\n  kill nukes Chromium's socket pool, and the resulting `ERR_NETWORK_CHANGED`\n  gets blamed on whatever you just changed.\n- **A throwaway `HERMES_HOME` has no backend.** The app logs `ECONNREFUSED` for\n  `hermes:api` and may exit on its own. The renderer still mounts and the DOM is\n  readable — read promptly, and don't mistake a self-exited probe for a broken\n  port. Chromium logs `DevTools listening on ws:\u002F\u002F127.0.0.1:\u003Cport>\u002F…` when it\n  binds; that line is the proof the port opened.\n- **Poll, don't probe once.** A just-launched app needs a second or two before\n  the port answers.\n- **Never dump the whole DOM.** The desktop renders hundreds of nodes and\n  `outerHTML` will bury your context. Project down to a small JSON object inside\n  the evaluated expression.\n- **Pass `match` to `CDP.connect`.** Without it you may attach to the pet\n  overlay, quick-entry window, or a devtools target instead of the main window.\n- **`cdp.eval` returns the value; raw `Runtime.evaluate` double-nests it**\n  (`.result.result.value`). Use the wrapper.\n- **`import.meta.env.DEV` is `true` under `vite dev`** in this repo. The note in\n  `apps\u002Fdesktop\u002Fscripts\u002Fprofile-typing-lag.md` claiming otherwise is stale.\n",{"name":5,"author":47,"license":14,"version":48,"metadata":49,"platforms":56,"description":7},"Hermes Agent","1.0.0",{"hermes":50},{"tags":51,"related_skills":54},[20,39,29,18,52,53],"ui-verification","self-inspection",[55,25,30],"node-inspect-debugger",[40,32,38],"main","05df7380981a2c4af868ce0fa57962ae0eea62a9","hermes\u002Fskills\u002Fsoftware-development\u002Finspecting-hermes-desktop-dom",0,"https:\u002F\u002Fgithub.com\u002Fjleechanorg\u002Fjleechan-skills","https:\u002F\u002Fgithub.com\u002Fjleechanorg","2026-11-14 14:55:35",{"source":8,"skillName":5,"commands":65,"prompt":75,"zipAvailable":76},[66,69,72],{"tool":67,"command":68},"npx","npx skills add jleechanorg\u002Fjleechan-skills --skill inspecting-hermes-desktop-dom",{"tool":70,"command":71},"bunx","bunx skills add jleechanorg\u002Fjleechan-skills --skill inspecting-hermes-desktop-dom",{"tool":73,"command":74},"pnpm","pnpm dlx skills add jleechanorg\u002Fjleechan-skills --skill inspecting-hermes-desktop-dom","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fjleechanorg\u002Fjleechan-skills\u002Fblob\u002Fmain\u002Fhermes\u002Fskills\u002Fsoftware-development\u002Finspecting-hermes-desktop-dom\u002FSKILL.md",true,[],[79,96,118,132,146,162],{"skillNo":80,"name":81,"nameZh":6,"description":82,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":83,"categories":84,"keywords":85,"publishedAt":42},"01M716Y5MTJ6GYJZ2ATXCJK8G4","instinct","Use when the user invokes \u002Finstinct or \u002Fin, or asks to \"message Instinct\", \"ask Instinct\", \"tell Instinct\", \"check Instinct\", or read replies from the configured peer assistant. iMessage first, WhatsApp Web as fallback.","https:\u002F\u002Fgithub.com\u002Fjleechanorg\u002Fjleechan-skills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Finstinct\u002FSKILL.md",[],[81,86,87,88,89,90,91,92,93,31,94,95],"user","when","replies","check","use","identity","whatsapp","gmail","message","ask",{"skillNo":97,"name":98,"nameZh":6,"description":99,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":100,"categories":101,"keywords":107,"publishedAt":42},"01M716Y4HF7FVVMJSA2CCVN5VF","hr","Compatibility alias for history-resume; produce the same fresh-state, provenance-aware resume briefing.","https:\u002F\u002Fgithub.com\u002Fjleechanorg\u002Fjleechan-skills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fhr\u002FSKILL.md",[102],{"categoryNo":103,"categoryName":104,"taxonomyType":105,"taxonomyTypeDesc":106},"01JBSEEDCAT000000000000038","人力资源","PROFESSION","适用职业",[98,108,109,110,111,112,113,114,115,116,117],"resume","compatibility","provenance","for","history","produce","alias","briefing","state","fresh",{"skillNo":119,"name":120,"nameZh":6,"description":121,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":122,"categories":123,"keywords":125,"publishedAt":42},"01M716Y1FFNFKFJYYKF8HQA6T8","history-resume","Resume briefing for the current repository branch or worktree using fresh state and admitted history sources.","https:\u002F\u002Fgithub.com\u002Fjleechanorg\u002Fjleechan-skills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fhistory-resume\u002FSKILL.md",[124],{"categoryNo":103,"categoryName":104,"taxonomyType":105,"taxonomyTypeDesc":106},[112,108,126,127,86,128,115,129,111,130,131,116,117],"history resume","branch","analysis","repository","worktree","sources",{"skillNo":133,"name":134,"nameZh":6,"description":135,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":136,"categories":137,"keywords":138,"publishedAt":42},"01M716XWXJ8EPHK4RH9T14TR85","grok","Alias for the canonical grokbot browser conversation workflow; \u002Fgrok talks to the Grok bot the same way \u002Fdot talks to Dot.","https:\u002F\u002Fgithub.com\u002Fjleechanorg\u002Fjleechan-skills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fgrok\u002FSKILL.md",[],[134,139,140,141,111,142,114,143,144,145],"dot","bot","workflow","canonical","conversation","browser","grokbot",{"skillNo":147,"name":148,"nameZh":6,"description":149,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":150,"categories":151,"keywords":152,"publishedAt":42},"01M70N9Q07DTE0EW5KFXMMMSJ0","codexa-bench","Compare `codexa` and normal `codex` on a fair split of comparable work by default; use `--strict` for duplicate runs of the exact same task.","https:\u002F\u002Fgithub.com\u002Fjleechanorg\u002Fjleechan-skills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Fcodexa-bench\u002FSKILL.md",[],[153,154,155,90,156,111,157,158,159,160,161],"codexa bench","work","split","default","duplicate","task","compare","normal","codex",{"skillNo":163,"name":164,"nameZh":6,"description":165,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":166,"licenseFileUrl":167,"sourceHtmlUrl":168,"categories":169,"keywords":181,"publishedAt":42},"01M6C24S2X60SP8BBFGAEKPEGW","frontend-design","Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, artifacts, posters, or applications (examples include websites, landing pages, dashboards, React components, HTML\u002FCSS layouts, or when styling\u002Fbeautifying any web UI). Generates creative, polished code and UI design that avoids generic AI aesthetics.","Apache-2.0","https:\u002F\u002Fgithub.com\u002Fjleechanorg\u002Fjleechan-skills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Ffrontend-design\u002FLICENSE.txt","https:\u002F\u002Fgithub.com\u002Fjleechanorg\u002Fjleechan-skills\u002Fblob\u002Fmain\u002F.claude\u002Fskills\u002Ffrontend-design\u002FSKILL.md",[170,175,178],{"categoryNo":171,"categoryName":172,"taxonomyType":173,"taxonomyTypeDesc":174},"01JBSEEDCAT000000000000009","前端开发","SCENARIO","使用场景",{"categoryNo":176,"categoryName":177,"taxonomyType":173,"taxonomyTypeDesc":174},"01JBSEEDCAT000000000000015","视觉设计",{"categoryNo":179,"categoryName":180,"taxonomyType":105,"taxonomyTypeDesc":106},"01JBSEEDCAT000000000000032","设计师",[182,183,184,90,185,186,187,86,188,189,190,191,35,192,193,194,195,196,197,198,41,199,200,201,202,203,87,204],"frontend","design","frontend design","generic","ui design","react","html","components","code","artifacts","aesthetics","Production","web components","landing","applications","quality","web","create","examples","with","react components","web ui","pages"]