Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
954 commits
Select commit Hold shift + click to select a range
65e9ff1
test: fix locators to camelCase
Mimidze Mar 16, 2026
fb87c7b
Merge pull request #454 from lidofinance/test/dashboard-tracking-clean
Mimidze Mar 17, 2026
be81ba1
fix: ability to change roles, set splits, claimer
exromany Mar 17, 2026
fc7e5f7
chore(deps): bump socket.io-parser from 4.2.5 to 4.2.6
dependabot[bot] Mar 19, 2026
b547931
feat: group page
exromany Mar 20, 2026
db6cd77
chore(deps): bump flatted from 3.3.1 to 3.4.2
dependabot[bot] Mar 20, 2026
3ebda89
feat: improve address-input and ens resolving
exromany Mar 20, 2026
74a76af
fix: invalidate cache on change operator or wallet address
exromany Mar 23, 2026
366e3fd
feat: invalidate cache on change operator or wallet
exromany Mar 23, 2026
47ec61a
fix: groups
exromany Mar 23, 2026
7ed955c
fix: hide last-rewards section if there are no reports yet
exromany Mar 23, 2026
004e18b
fix: update sdk
exromany Mar 24, 2026
abf996a
feat: setup wc wallet for speed up tests (#455)
Vorobeyko Mar 25, 2026
b0e4d04
feat: operator switcher for curated module
exromany Mar 26, 2026
35dffc4
fix: create curated operator owner chip
exromany Mar 26, 2026
82ce94d
fix: add-keys confirm text
exromany Mar 26, 2026
e31cc0a
fix: disable submit button if form is clean
exromany Mar 26, 2026
bd52e6a
fix: hide CSM related add-keys info for CM
exromany Mar 26, 2026
ea9a571
fix: add-keys page subtitle
exromany Mar 26, 2026
e26bfb8
fix: change address capitalize
exromany Mar 26, 2026
effbab0
fix: change address validation
exromany Mar 26, 2026
0e5be10
fix: disable back button while submitting new operator
exromany Mar 26, 2026
82a077f
feat: change operator after creating
exromany Mar 26, 2026
afe3253
chore: update Playwright and related dependencies to latest versions …
Vorobeyko Mar 26, 2026
079f3a7
Merge remote-tracking branch 'origin/develop' into feature/csm-plus-cm
exromany Mar 26, 2026
3a58e61
fix: operator-switcher no metadata for CSM
exromany Mar 26, 2026
d3ab686
chore(deps): bump picomatch from 2.3.1 to 2.3.2
dependabot[bot] Mar 26, 2026
8a2f723
fix: remove extra dot
exromany Mar 27, 2026
29431f3
fix: word break in tx modal
exromany Mar 27, 2026
3b0448d
fix: stake & keys
exromany Mar 27, 2026
fe1d21b
fix: keys breakdown style and badges
exromany Mar 27, 2026
ef97801
fix: go to [Roles -> Settings] tab
exromany Mar 27, 2026
a85d613
fix: addres hide error if untouched
exromany Mar 28, 2026
2f8c552
fix: tooltip for next rewards distribution
exromany Mar 28, 2026
9920fd2
fix: open modal on group page
exromany Mar 28, 2026
952cca0
feat: unify back button
exromany Mar 29, 2026
a822327
feat: improve deposit-data input
exromany Mar 29, 2026
61d96dc
feat: claim bond - sources info
exromany Mar 29, 2026
48ee6a6
Merge remote-tracking branch 'origin/develop' into feature/invalidate…
exromany Mar 30, 2026
18711bd
fix: update sdk
exromany Mar 30, 2026
0c55268
fix: remove link from placeholder
exromany Mar 31, 2026
6ba0847
Merge pull request #470 from lidofinance/feature/invalidate-cache
Mimidze Mar 31, 2026
7685dad
fix: update matomo pkg
exromany Mar 31, 2026
cabcb8e
Merge pull request #475 from lidofinance/fix/update-matomo
Mimidze Apr 1, 2026
02aa9be
fix: update sdk
exromany Apr 1, 2026
cde6582
Merge pull request #476 from lidofinance/develop
Mimidze Apr 1, 2026
d3762cd
fix: stake and keys - badge & amount
exromany Apr 3, 2026
dd83ca5
fix: desposit-data input placeholder
exromany Apr 3, 2026
d50f835
fix: target limit
exromany Apr 3, 2026
146bff1
fix: update sdk
exromany Apr 3, 2026
56f73df
fix: show metadata tab only inside operator
exromany Apr 3, 2026
a3900d0
fix: show badge more-keys
exromany Apr 3, 2026
b1a1494
fix: more-keys error state on dashboard
exromany Apr 3, 2026
57b2781
chore(deps): bump defu from 6.1.4 to 6.1.6
dependabot[bot] Apr 4, 2026
5427a48
feat: unlock bond uses bond balance
exromany Apr 4, 2026
f3ee545
fix: update sdk
exromany Apr 4, 2026
b52aea9
feat: refactor form flow for unlock-bond
exromany Apr 5, 2026
b1f903c
feat: reafctor forms flow 1
exromany Apr 6, 2026
2fa32b7
fix: update ics round
exromany Apr 7, 2026
4868696
fix: round 5 assessed date
exromany Apr 7, 2026
050e09a
Merge pull request #478 from lidofinance/fix/ics-round-update
Mimidze Apr 7, 2026
439c7a0
feat: refactor forms flow 2
exromany Apr 7, 2026
1588ae0
fix: testable error wrapper
exromany Apr 7, 2026
77e85db
Merge pull request #479 from lidofinance/develop
Mimidze Apr 7, 2026
c129c14
chore(deps): bump lodash from 4.17.23 to 4.18.1
dependabot[bot] Apr 7, 2026
45c7289
fix: refactor forms flow 3
exromany Apr 8, 2026
696f3a7
feat: refactor forms flow 4
exromany Apr 8, 2026
2650240
fix: improve csp
exromany Apr 9, 2026
33244c2
feat: refactor forms flow 5
exromany Apr 9, 2026
1c76169
feat: update claim-bond WIP
exromany Apr 9, 2026
01f34d6
fix: types in test
exromany Apr 10, 2026
e94cb96
Merge pull request #480 from lidofinance/dependabot/npm_and_yarn/loda…
exromany Apr 10, 2026
f052cd9
Merge pull request #477 from lidofinance/dependabot/npm_and_yarn/defu…
exromany Apr 10, 2026
8602c8a
Merge pull request #473 from lidofinance/dependabot/npm_and_yarn/pico…
exromany Apr 10, 2026
fc31fd6
Merge pull request #466 from lidofinance/dependabot/npm_and_yarn/sock…
exromany Apr 10, 2026
bcbd779
Merge pull request #467 from lidofinance/dependabot/npm_and_yarn/flat…
exromany Apr 10, 2026
30a4d23
Merge pull request #457 from lidofinance/dependabot/npm_and_yarn/svgo…
exromany Apr 10, 2026
203b86f
fix: remove tests from eslintignore
exromany Apr 10, 2026
85597b5
fix: refactor tx-modal retry
exromany Apr 11, 2026
821d492
fix: claim bond empty state
exromany Apr 13, 2026
c41531b
feat: key status triggered-ejection
exromany Apr 13, 2026
64dd9af
Merge pull request #482 from lidofinance/fix/improve-csp
Mimidze Apr 13, 2026
58b3aec
Merge pull request #485 from lidofinance/develop
Mimidze Apr 13, 2026
4fd42e3
fix: last rewards tx hash - hide if no hash
exromany Apr 13, 2026
6d8c228
Merge branch 'feat/cm-forms-flow' into feature/csm-plus-cm
exromany Apr 13, 2026
22e5e5c
chore: add devnet settings
exromany Apr 13, 2026
b03810e
chore(deps): bump follow-redirects from 1.15.9 to 1.16.0
dependabot[bot] Apr 14, 2026
ca542f9
fix: update sdk
exromany Apr 14, 2026
5ef8928
fix: fixes
exromany Apr 14, 2026
cbe463e
fix: role actions, loader errors, modal form
exromany Apr 15, 2026
59679ab
chore: update devnet
exromany Apr 15, 2026
a10d6e9
chore: update devnet
exromany Apr 15, 2026
7e8cc67
chore: more devnet
exromany Apr 15, 2026
3f35c9c
chore(deps): bump hono from 4.12.3 to 4.12.14
dependabot[bot] Apr 16, 2026
d0b0734
fix: update group text
exromany Apr 16, 2026
0e8e3d0
chore: cleanup devnet
exromany Apr 16, 2026
a221bf3
Merge remote-tracking branch 'origin/develop' into feature/csm-plus-cm
exromany Apr 16, 2026
12c36c2
fix: update sdk with changed invite type
exromany Apr 16, 2026
39bb33c
fix: packages audit fix
exromany Apr 16, 2026
9b002ed
Merge branch 'fix/test-types' into feature/csm-plus-cm
exromany Apr 16, 2026
9a0ba41
fix: capitalize
exromany Apr 17, 2026
6b506fc
fix: validation address-input
exromany Apr 17, 2026
95be213
fix: stake and keys component
exromany Apr 17, 2026
4597c9b
fix: group page
exromany Apr 18, 2026
61efab9
fix: create-curated-operator styles
exromany Apr 21, 2026
047e17b
fix: radio button
exromany Apr 21, 2026
9dccb5f
fix: claim bond flow
exromany Apr 22, 2026
6140391
fix: max amount
exromany Apr 22, 2026
9963753
fix: add bond wsteth rate
exromany Apr 22, 2026
3df7291
feat: accept invite on change-role form
exromany Apr 22, 2026
406a8a7
fix: submit no changes in splitters
exromany Apr 22, 2026
45db43f
fix: updated sdk
exromany Apr 22, 2026
22ff1a7
Merge remote-tracking branch 'origin/main' into feature/csm-plus-cm
exromany Apr 23, 2026
ab712d9
Merge branch 'feature/csm-plus-cm' into develop-cm
exromany Apr 23, 2026
da8f2e2
chore: update env exmape
exromany Apr 23, 2026
ce707b8
Merge remote-tracking branch 'origin/develop' into develop-cm
exromany Apr 23, 2026
2dd2929
Merge branch 'feature/csm-plus-cm' into develop-cm
exromany Apr 23, 2026
4493a2b
fix: table styles
exromany Apr 23, 2026
ec9a695
fix: after walkthrough call
exromany Apr 23, 2026
9ee5e61
Merge pull request #487 from lidofinance/dependabot/npm_and_yarn/hono…
exromany Apr 24, 2026
37a2dd2
Merge pull request #486 from lidofinance/dependabot/npm_and_yarn/foll…
exromany Apr 24, 2026
6608035
chore: build-push-harbor
exromany Apr 24, 2026
5212c42
fix: add api/ready
exromany Apr 24, 2026
9354e08
chore: log module
exromany Apr 24, 2026
42538a5
fix: normalize rpc url ended with slash
exromany Apr 24, 2026
1ddbc33
fix: update sdk for unknown module
exromany Apr 24, 2026
d717c8b
fix: build with version
exromany Apr 26, 2026
e36cccc
fix: splitter share placeholder
exromany Apr 26, 2026
a758aab
fix: navigation, gates, nav items
exromany Apr 27, 2026
66299c7
fix: show commit in version
exromany Apr 27, 2026
b34b8fb
feat: claim bond + splitters
exromany Apr 27, 2026
e064d97
Merge branch 'feature/csm-plus-cm' into develop-cm
exromany Apr 27, 2026
17983f3
fix: claim bond
exromany Apr 29, 2026
f8e7a64
fix: after call 2
exromany Apr 29, 2026
2793fdb
fix: claim bond options with splitters
exromany Apr 29, 2026
901fb1a
Merge branch 'feature/csm-plus-cm' into develop-cm
exromany Apr 29, 2026
be8bcf5
fix: texts
exromany Apr 30, 2026
4eab842
Merge branch 'feature/csm-plus-cm' into develop-cm
exromany Apr 30, 2026
21cee42
Merge branch 'develop' into feature/csm-plus-cm
exromany Apr 30, 2026
8fc303a
chore: remove ci changes
exromany Apr 30, 2026
326ba37
Merge pull request #490 from lidofinance/feature/csm-plus-cm
exromany Apr 30, 2026
df1501e
chore(deps): bump brace-expansion from 1.1.11 to 1.1.14
dependabot[bot] Apr 30, 2026
989d2da
fix: texts
exromany May 3, 2026
9cbc088
fix: claim options
exromany May 4, 2026
d4d1983
fix: update preview
exromany May 4, 2026
c4e6b84
fix: simple moduleMeta
exromany May 4, 2026
013976c
Merge remote-tracking branch 'origin/develop' into develop-cm
exromany May 4, 2026
bd29702
chore: build push harbor
exromany May 4, 2026
5725ef6
Merge pull request #491 from lidofinance/dependabot/npm_and_yarn/brac…
exromany May 4, 2026
65f345c
Merge pull request #453 from lidofinance/dependabot/github_actions/ac…
exromany May 4, 2026
3c4c1e3
fix: remove md
exromany May 5, 2026
00143ef
fix: cm other module banner text
exromany May 5, 2026
a29c1d9
Merge branch 'develop-cm' into fix/cm
exromany May 5, 2026
cf0dcac
fix: text
exromany May 5, 2026
a4aac44
Merge pull request #492 from lidofinance/chore/build-push-harbor
exromany May 5, 2026
58441a1
fix: redirect for keys-upload for RA only
exromany May 5, 2026
1661553
chore(deps): bump docker/build-push-action from 6 to 7
dependabot[bot] May 5, 2026
4add360
chore(deps): bump actions/checkout from 4 to 6
dependabot[bot] May 5, 2026
2c7caab
chore(deps): bump docker/login-action from 3 to 4
dependabot[bot] May 5, 2026
a6bd780
Merge branch 'develop-cm' into fix/cm
exromany May 5, 2026
07b1e20
fix: build manifest.json
exromany May 5, 2026
648f07a
Merge branch 'develop-cm' into fix/cm
exromany May 5, 2026
6a5dcbe
fix: dipositable keys without weight
exromany May 8, 2026
9ffd03c
fix: operator type EEO
exromany May 8, 2026
83ed441
feat: add FAQ for CM
exromany May 11, 2026
3d3cffe
fix: claim bond options
exromany May 11, 2026
f31191d
fix: skip share-limit waiting for CM add-keys
exromany May 11, 2026
ac36965
Merge branch 'develop-cm' into fix/cm
exromany May 11, 2026
1fd0de0
Merge pull request #493 from lidofinance/fix/cm
exromany May 12, 2026
eddb8d4
fix: infinite loop on create page
exromany May 12, 2026
9e67d63
fix: select file for FF
exromany May 12, 2026
e6bb5e9
fix: claim bond long option
exromany May 12, 2026
0a88c96
fix: claim bond modal
exromany May 12, 2026
113bfd5
feat: added data attr for elements
Vorobeyko May 13, 2026
f19533d
fix: address review feedback on data-testid PR
exromany May 13, 2026
4040c13
Merge pull request #506 from lidofinance/feat/data-testids
exromany May 13, 2026
2951c1c
fix: grammar tx modal
exromany May 13, 2026
50dc26c
feat: qa-config page to setup custom rpc and cl api
exromany May 14, 2026
9a75b5a
feat: env for ipfs gateways and surveys api
exromany May 14, 2026
86aa44b
fix: qa-config layout dummy
exromany May 14, 2026
8920d28
feat: update CM faq
exromany May 19, 2026
d7235c8
fix: key comment link
exromany May 19, 2026
5e2fc4a
feat: rename stealing to delayed-penalty
exromany May 21, 2026
d0f45b6
fix: update Node.js version to 24 and clean up workflow files (#509)
Vorobeyko May 26, 2026
222adbc
fix: update Playwright and related dependencies to latest versions (#…
Vorobeyko May 29, 2026
5932921
feat: keys-cache used internally in sdk
exromany May 21, 2026
c7db194
fix: test dulicated-keys
exromany May 21, 2026
9c42eee
fix: revert group names
exromany May 21, 2026
b9e875f
fix: dummy qa-config
exromany May 21, 2026
2903fe6
fix: downgrade sdk
exromany May 22, 2026
0035c78
fix: current-stake without external-stake
exromany May 28, 2026
4cb827e
feat: group name
exromany May 28, 2026
6fcb021
fix: adapt curated gates to gateName-based SDK API
exromany Jun 1, 2026
ace6ac4
feat: keep IDVTC operator type metadata
exromany Jun 1, 2026
f54cda3
chore: ci
exromany May 28, 2026
f8dc9ea
fix: update Node.js version to 24 and clean up workflow files (#509)
Vorobeyko May 26, 2026
af9f726
fix: update Playwright and related dependencies to latest versions (#…
Vorobeyko May 29, 2026
6e7c39e
chore(deps): bump reef-knot to 8.1.0
exromany Jun 1, 2026
1c7f2dd
chore(deps): patch dependabot security advisories via resolutions
exromany Jun 1, 2026
d8cf5f0
chore(deps): bump uuid to v14 to patch advisories
exromany Jun 1, 2026
d948b00
Merge remote-tracking branch 'origin/develop' into develop-cm
exromany Jun 1, 2026
f7dc3ec
chore: ci
exromany Jun 2, 2026
912c3c2
Merge pull request #515 from lidofinance/chore/sync-develop-cm
exromany Jun 2, 2026
9acae05
feat: update inbox requests copy
exromany Jun 2, 2026
986af6f
Merge pull request #496 from lidofinance/dependabot/github_actions/do…
exromany Jun 3, 2026
880ff75
Merge pull request #497 from lidofinance/dependabot/github_actions/ac…
exromany Jun 3, 2026
f0bb0b2
feat: add helper text to operator name and description inputs
exromany Jun 2, 2026
1acb810
fix: wrap view-mode change-role info in form so Accept invite submits
exromany Jun 2, 2026
25c157a
Merge pull request #519 from lidofinance/chore/sync-develop-cm
exromany Jun 3, 2026
4a5aa37
Merge pull request #498 from lidofinance/dependabot/github_actions/do…
exromany Jun 3, 2026
93f7a05
fix: delayed-penalty on cm
exromany Jun 4, 2026
eeccc81
fix: stack label and address in change-role/claimer tx modals
exromany Jun 4, 2026
868cc09
fix: show simple message on wallet sign timeout error
exromany Jun 4, 2026
cf911ff
fix: enforce sentence-ending dot rule in UI copy
exromany Jun 5, 2026
f5ce676
fix: harden address-validation file loader against IO errors
exromany Jun 6, 2026
93ec47f
fix: infinite load page without operatro
exromany Jun 6, 2026
aba22cc
tests: added tests for curated module (#474)
Vorobeyko Jun 9, 2026
1552e3e
fix: type config.module as MODULE_NAME enum
exromany Jun 13, 2026
31cff81
fix: align test types with sdk module rename & node service api
exromany Jun 13, 2026
cddbac0
fix: capitalize "Not set" labels and use config links in cm
exromany Jun 13, 2026
0998751
Merge develop-cm into develop
exromany Jun 15, 2026
778754c
Use SecGuardReporter to hide sensetive env in pw report (#520)
jake4take Jun 15, 2026
2b0fef8
test: update event name for detailed link in welcome page test
Mimidze Jun 16, 2026
694b6ac
Merge remote-tracking branch 'origin/develop' into develop-cm
exromany Jun 16, 2026
9248e33
Merge branch 'develop-cm' into chore/sync-develop-cm
exromany Jun 16, 2026
c757b90
Merge pull request #521 from lidofinance/chore/sync-develop-cm
exromany Jun 18, 2026
a371e49
Merge remote-tracking branch 'origin/develop' into fix/csm-e2e-tests
Mimidze Jun 19, 2026
217e93f
test: fix visibility checks for latest rewards distribution
Mimidze Jun 19, 2026
7d52705
test: remove skipped test 144 for "Stuck keys found" field
Mimidze Jun 19, 2026
3740c2d
chore: replace Harbor registry endpoint
Ziars Jun 22, 2026
9dbeabf
test: fixes after review
Mimidze Jun 23, 2026
6173287
test: removed duplicate test skips
Mimidze Jun 23, 2026
93de5e4
feat: add e2e test workflows and setup actions for CSM/CM modules (#529)
Vorobeyko Jun 23, 2026
a64087f
feat: siwe nonce handshake for surveys api auth
exromany Jun 22, 2026
7042572
fix: migrate survey API to lido.tools domains
exromany Jun 23, 2026
acfccf4
test: fix why modal test
Mimidze Jun 23, 2026
b3bea82
test: fixed expected days verification for rewards distribution
Mimidze Jun 23, 2026
d16227e
test: remove skipped test for delayed oracle report
Mimidze Jun 23, 2026
f839f9f
Merge pull request #531 from Ziars/chore/replace-harbor-registry-endp…
madlabman Jun 24, 2026
4711628
fix: update button names and improve test timeout handling (#535)
Vorobeyko Jun 24, 2026
3c934f8
Merge pull request #522 from lidofinance/fix/csm-e2e-tests
Mimidze Jun 24, 2026
ef2f88e
Merge pull request #534 from lidofinance/fix/survey-api-auth
Mimidze Jun 25, 2026
8e63c66
test: add data-testid and update expected text in tests (#538)
Mimidze Jun 26, 2026
5e8ec35
feat: surveys-sdk + IDVTC apply/claim flows (#518)
exromany Jul 1, 2026
c573f29
tests: add tests for idvtc (#537)
Vorobeyko Jul 2, 2026
ad1e1b5
chore(deps): bump docker/setup-buildx-action from 3.3.0 to 4.2.0
dependabot[bot] Jul 2, 2026
ca30735
fix(matomo): distinct page events for settings and type sub-pages, fi…
exromany Jul 6, 2026
1551313
fix: assorted claim-bond, add-keys, deposit-data & tx-modal fixes (#539)
exromany Jul 7, 2026
5e27252
Merge pull request #541 from lidofinance/dependabot/github_actions/do…
exromany Jul 8, 2026
d5acdfc
test: add address blacklist validation tests for operators: (#548)
Vorobeyko Jul 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
15 changes: 15 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"presets": [
[
"next/babel",
{
"preset-env": {
"exclude": ["transform-exponentiation-operator"]
}
}
]
],
"plugins": [
"babel-plugin-styled-components"
]
}
2 changes: 2 additions & 0 deletions .claude/skills/visual-verify/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Auto-installed csm-dev-wallet + generated screenshots (not source)
.cache/
178 changes: 178 additions & 0 deletions .claude/skills/visual-verify/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
---
name: visual-verify
description: >-
Use when you need to SEE, screenshot, preview, or visually QA how a page of the running CSM or CM
widget looks — connected as a specific wallet address or node operator, or in the disconnected/welcome
state — which a plain headless browser can't reach (it has no wallet). Opens the running app (localhost
or a testnet URL), navigates any route, optionally in dark/light theme, a mobile/desktop viewport, or
cropped to one element, and captures a screenshot plus any console/network errors. E.g. "show the
dashboard as operator 4", "settings in dark mode", "the bond page on mobile", "screenshot the welcome
screen", or "open cm.testnet.fi as operator 5". NOT for: writing unit/e2e tests, debugging
connector/wallet code, building UI features, or comparing against Figma.
---

# Visual verification of the running app

This app is a Web3 dApp: every meaningful page requires a connected wallet. A vanilla automated
browser has no `window.ethereum`, so the connect modal has nothing to click and you only ever see
the welcome screen. This skill solves that with **csm-dev-wallet** — a dev wallet extension that
injects a provider and lets you connect as _any_ address or node operator without keys or signing
(the app runs on Hoodi testnet, where watch-only is enough to render every connected page).

## Prerequisites

- A target app must be reachable — the local dev server at `http://localhost:3000` (`yarn dev`), the
CM instance (e.g. `localhost:3001`), or a remote testnet (`--url https://csm.testnet.fi`). This skill
does **not** start anything — check first (`curl -sI <url>`), and ask the user to run `yarn dev` if local is down.
- Which **module** (CSM vs CM) and **chain** the target runs on are detected automatically from the app
itself, so the same command works against any instance — no need to know or pass them.
- `csm-dev-wallet` is auto-installed into `.claude/skills/visual-verify/.cache/` on first run (it's a
QA tool, deliberately kept out of the project's `package.json`). `playwright` is reused from the repo.

## Quickstart — screenshot any page in any state

```bash
# Dashboard, connected as node operator #4 (resolves the operator's manager address automatically)
node .claude/skills/visual-verify/scripts/verify.mjs --operator 4 --route /

# Settings, as operator #4's rewards address
node .claude/skills/visual-verify/scripts/verify.mjs --operator 4 --role rewards --route /settings

# Any route, connected as a raw address
node .claude/skills/visual-verify/scripts/verify.mjs --address 0xd8dA…96045 --route /keys

# A different instance — the CM-module app, or a remote testnet. Module + chain auto-detected from the URL.
node .claude/skills/visual-verify/scripts/verify.mjs --url http://localhost:3001 --operator 2
node .claude/skills/visual-verify/scripts/verify.mjs --url https://cm.testnet.fi --operator 5

# Dark mode, and a mobile-width layout (combine freely)
node .claude/skills/visual-verify/scripts/verify.mjs --operator 4 --theme dark
node .claude/skills/visual-verify/scripts/verify.mjs --operator 4 --viewport mobile --theme dark

# Just one element (cropped, scrolled into view) instead of the whole page
node .claude/skills/visual-verify/scripts/verify.mjs --operator 4 --selector '[data-testid="accountSectionHeader"]'

# The disconnected/welcome state — no wallet at all (operator/address not required)
node .claude/skills/visual-verify/scripts/verify.mjs --no-connect --route /

# Watch it happen live, and leave the browser open to poke around
node .claude/skills/visual-verify/scripts/verify.mjs --operator 12 --headed --keep-open
```

It prints the resulting `STATE` (url / connected / account / operator), confirms the requested operator
is the one actually shown, a **page-health** line (console errors, uncaught exceptions, failed + 4xx/5xx
requests), and a screenshot path — then **Read the PNG to actually look at it**. The health line is what
catches a page that _looks_ fine but is actually broken (e.g. a dev server serving 404 chunks). If a run
fails at any step, it still saves a `FAILED-*.png` of wherever it got stuck (and reports its path) — a
failure image usually shows the cause (a modal that never opened, a blank card, the wrong route).

**`--operator N` guarantees operator N is displayed.** Many operators share an address (e.g. one address
is the rewards address of operators 4, 36 and 318). Connecting only pins the _address_; the app then shows
a default operator (the first or last-cached), which may be a sibling, not N. So after connecting the
script switches the in-app operator selection to N and verifies it — if N isn't available for the resolved
address, it errors and lists what _is_ available. (`--address` has no specific operator, so no switch.)

Default output is `.cache/shots/<module>-<tag>.png` (prefixed with module + any theme/viewport variant
so they don't collide); override with `--out path.png` (relative paths resolve to cwd). Flags:
`--url <origin>` (default `$APP_ORIGIN` / `localhost:3000`) | `--operator N` | `--address 0x…` |
`--role manager|rewards|owner` (default `manager`) | `--route /path` | `--theme light|dark` |
`--viewport mobile|tablet|desktop|WxH` | `--selector <css>` (shoot one element) |
`--no-connect` (capture with no wallet; operator/address not required) | `--json` |
`--module csm|cm` | `--chain 560048` | `--headed` | `--keep-open` | `--full` (full-page) |
`--out file.png`. **`--module` and `--chain` are auto-detected from the target URL** — only pass them to override.

`--json` emits one structured object on **stdout** (progress logs go to stderr) with the connection
details, `state`, the screenshot path, and `health` + full `diagnostics` (the console/network errors).
Use it when an agent needs to act on the result — `health.total > 0` is the machine-readable "this page
has problems" signal even when the screenshot looks fine. On failure it prints `{ "ok": false, "error" }`
and exits non-zero.

`--theme` works via `prefers-color-scheme` (the app honours it), set before first paint and verified by
page-background luminance, with the header theme toggler as fallback — so it's reliable even at mobile
widths where the toggler hides in a menu. `--viewport` presets: mobile `390×844`, tablet `768×1024`,
desktop `1280×800` (or pass an explicit `WIDTHxHEIGHT`).

## Finding operators

To pick an operator — or find an address that controls several (needed to exercise the in-app
operator switcher, which changes operator _without_ a wallet change):

```bash
node .claude/skills/visual-verify/scripts/operators.mjs # summary + multi-operator addresses
node .claude/skills/visual-verify/scripts/operators.mjs --id 4 # full details for operator #4
```

## How it connects (the non-obvious bits)

These quirks are already handled in `scripts/lib.mjs`; understand them before writing custom flows:

- **Connection is seeded, not clicked (with a modal fallback).** Setting `eth_accounts` alone does NOT
auto-connect — wagmi/reef-knot only adopt a connection from persisted storage or an explicit connector
call. So `connectAs` writes the exact 4 `localStorage` keys a real connect leaves behind (terms-accepted
flag + `wagmi.recentConnectorId`/`reconnect-wallet-id` + the `wagmi.store` connection record) via
`addInitScript` **before load**, and the app reconnects the injected wallet on boot — no clicks. If that
reconnect doesn't take (e.g. wagmi bumps `wagmi.store`'s schema or the `reef-knot_accept-terms_n2`
version suffix drifts), it falls back to the **proven modal flow**: `connectBtn` → tick the Terms
checkbox (it gates the wallet buttons) → click the **"Browser"** option (the injected provider shows up
under the pinned `browserExtension` connector, not by the wallet's own name).
- **The header chip re-renders asynchronously** after any navigation, reload, or account change (wagmi
reconnects, balances fetch). Always wait for the header to settle into connected-or-disconnected
before reading state or screenshotting, or you capture a blank chip. `settle()` does this.
- **Wallet account vs active operator are two layers.** One address can manage many operators; the app's
switcher (`data-testid="nodeOperatorHeader"`) changes the active operator with no wallet event. The
in-app operator selection is connection-scoped — it resets to the default operator on reconnect/reload,
which is why `connectAs` re-asserts it (via `ensureOperator`) _after_ the final navigation, not before.

## Writing custom multi-step flows

For scenarios beyond a single screenshot (persistence checks, account switching, the operator switcher,
disconnect/reconnect), import the library instead of shelling out to the CLI:

```js
import { connectAs, ensureOperator, readState, settle, HOODI } from './lib.mjs';

const { context, wallet, page } = await connectAs({
operatorId: 318,
route: '/settings',
});
await wallet.switchAccount(page, '0xba99…26af'); // change wallet account → app reacts live
await settle(page);
await ensureOperator(page, 36); // switch in-app operator (no wallet change)
console.log(await readState(page)); // { url, connected, account, operator }
await page.screenshot({ path: 'after-switch.png' });
await context.close();
```

`connectAs(...)` returns Playwright's `context`/`page` plus the dev-wallet `wallet` controller, and (for
`operatorId`) guarantees that operator is active. Helpers: `ensureOperator(page, id)` (in-app switch +
verify), `currentOperatorId(page)`, `readState`, `settle`, `connectModal`. Key `wallet` methods:
`switchAccount(page, addr)`, `switchNetwork(page, chainId)`, `disconnect(page)`,
`selectOperator(page, id, role)`, `refreshOperators(page, chainId, module)`, `getOperator(page, id, …)`.
Full controller API, the underlying `wallet_test*` RPC primitives (for drivers that can't use the
helper), and a **dev-browser fallback** (for headed/persistent sessions) are in
[references/advanced.md](references/advanced.md).

## Key app facts

- Network: Hoodi testnet, `chainId 560048` (auto-detected per instance). The app's RPC proxy
(`<origin>/api/rpc`) is reused to resolve operators.
- **CSM vs CM**: the app serves one module per instance (`MODULE` env). They have _different_ operator
sets, so an id valid in CSM may not exist in CM. `operators.mjs --url <cm-origin>` lists the right set.
The connect flow, header testids, and switcher are shared across both modules.
- Header testids: `accountSectionHeader` (wallet chip), `nodeOperatorHeader` (active operator + switcher),
`connectBtn` (shown only when disconnected). Account modal: `disconnectBtn`, `connectedAddress`.
Operator switcher rows: `switchModalOperatorRow`, with a "Switch" button per non-current row.
- Routes are normal Next.js paths: `/`, `/keys`, `/settings` (redirects to a sub-tab like
`/settings/roles`), etc. Use whatever the app's nav exposes.
- `MODULE` (csm/cm) is set by the server env; pass `--module` to match if you've switched it.

## Troubleshooting

- **Welcome screen / never connects** → app likely on a different `MODULE` or chain than you passed,
or the connect modal changed. Re-run with `--headed` to watch, and check the testids above still exist.
- **`ECONNREFUSED` / blank page** → dev server isn't running; start `yarn dev`.
- **Slow first load** → the dev server cold-compiles on first hit; navigation auto-retries (commit +
app-shell wait, 3 attempts). If it still reports "never became ready", the server is stuck — restart `yarn dev`.
- **Operator resolve fails** → `/api/rpc` proxy unreachable or the id doesn't exist on this chain; try
`operators.mjs` to list valid ids.
- **Chromium missing** → run `yarn playwright install chromium` (the repo's documented setup step).
Loading