diff --git a/.changeset/step-commands-shadow-dom.md b/.changeset/step-commands-shadow-dom.md new file mode 100644 index 0000000..6f5de2c --- /dev/null +++ b/.changeset/step-commands-shadow-dom.md @@ -0,0 +1,6 @@ +--- +"@karnstack/reins": patch +"@reins/extension": patch +--- + +Step commands see web components and custom controls. `reins snapshot` now lists elements inside open shadow roots (a site's search button, a `Sort by` menu built as a web component) and names them the way `reins do` does (through `aria-labelledby`, labels, shadow roots and slots), and `--ref` reaches them in `click`, `type`, `fill`, `hover`, `select` and the rest. `--selector` stays light-DOM CSS. Each snapshot now re-issues its refs, so a ref no longer lands on an element hidden since the previous snapshot (the "element has zero size" failures on wizards and tab panels). A click on a control with no box of its own (a native radio or checkbox shrunk to 0×0 under a styled card, or a `display: contents` wrapper) presses its visible label, custom radio/switch it sits in, or first rendered child instead. diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c4afa59..cd775c2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -26,10 +26,16 @@ jobs: steps: - uses: actions/checkout@v7.0.0 - uses: jdx/mise-action@v4.2.0 + # Same Chrome as ci.yml, so the extension's real-browser suite runs the + # same way here as it did on the PR. + - uses: browser-actions/setup-chrome@v2.2.0 + id: chrome - run: pnpm install --frozen-lockfile - run: pnpm lint - run: pnpm typecheck - run: pnpm test + env: + REINS_TEST_CHROME: ${{ steps.chrome.outputs.chrome-path }} - run: pnpm build - name: Version or publish (changesets) diff --git a/docs/benchmarks/2026-09-reins-do.md b/docs/benchmarks/2026-09-reins-do.md index a9626af..212be03 100644 --- a/docs/benchmarks/2026-09-reins-do.md +++ b/docs/benchmarks/2026-09-reins-do.md @@ -443,7 +443,7 @@ claude.ai connectors, so their definitions were in the context too). **What the step-by-step arm measures.** It is Claude plus reins' step commands, and some of its failures are the step commands': `reins snapshot` does not read shadow roots (mdn, openlibrary) and reported "zero size" on -controls in fx-wizard and fx-settings. A better step toolkit, or a Claude +controls in fx-wizard and fx-settings. Both were fixed after this benchmark (0.6.1: the snapshot reads open shadow roots, and stale refs from an earlier snapshot no longer point at hidden elements). The fx-wizard page also opened with its modal already showing, for both arms, because a CSS rule overrode `hidden`; that fixture bug was fixed afterwards too. A better step toolkit, or a Claude allowed to navigate by URL or use other tabs, would score higher and differ in speed and cost. diff --git a/packages/cli/scripts/bench/fixtures/wizard.html b/packages/cli/scripts/bench/fixtures/wizard.html index 125e6e2..3da52d1 100644 --- a/packages/cli/scripts/bench/fixtures/wizard.html +++ b/packages/cli/scripts/bench/fixtures/wizard.html @@ -16,6 +16,7 @@ button.secondary { background: #fff; color: #2f3e6e; } button:disabled { opacity: .5; cursor: not-allowed; } .backdrop { position: fixed; inset: 0; background: rgba(20, 24, 40, .55); display: flex; align-items: center; justify-content: center; } + .backdrop[hidden] { display: none; } .modal { background: #fff; border-radius: 10px; width: 520px; max-width: calc(100% - 32px); box-shadow: 0 20px 60px rgba(0,0,0,.3); } .modal header { background: #fff; color: #1a1a1a; border-bottom: 1px solid #dfe3e8; border-radius: 10px 10px 0 0; display: flex; justify-content: space-between; align-items: center; } .modal header button { all: unset; cursor: pointer; font-size: 20px; color: #666; padding: 0 4px; } diff --git a/packages/extension/src/lib/actionability.ts b/packages/extension/src/lib/actionability.ts index 26fcf44..45ba446 100644 --- a/packages/extension/src/lib/actionability.ts +++ b/packages/extension/src/lib/actionability.ts @@ -35,7 +35,16 @@ export type ProbeResult = ( * reaches the element; read it back with `readProbe`. * * With `node`, the target is the Jev node cache entry (`reins do` observed it - * by id); `selector` then only names it in messages. + * by id); with `locate`, whatever that function returns (a ref looked up + * through shadow roots). `selector` then only names it in messages. + * + * A target with no box of its own is pressed where it shows: a native radio + * or checkbox shrunk to 0×0 (or display:none) under a styled card is pressed + * through its visible