free-pi-cli 0.6.2 → 0.6.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1 -1
- package/dist/{main-cwwgr8bh.js → main-2mvzsazb.js} +377 -65
- package/package.json +1 -1
- package/skills/ux-flow/SKILL.md +200 -0
- package/skills/ux-flow/references/simplification-heuristics.md +103 -0
- package/skills/ux-paths/SKILL.md +196 -0
- package/skills/ux-paths/references/path-categories.md +169 -0
- package/skills/ux-visual/SKILL.md +252 -0
- package/skills/ux-visual/references/layout-audit.js +145 -0
- package/skills/ux-visual/references/solution-rubric.md +70 -0
- package/skills/ux-visual/references/visual-heuristics.md +102 -0
- package/skills/ux-visual/templates/report-template.md +29 -0
- package/skills/ux-walker/SKILL.md +251 -0
- package/skills/ux-walker/references/action-patterns.md +75 -0
- package/skills/ux-walker/references/geometry-audit.js +82 -0
- package/skills/ux-walker/references/issue-template.md +110 -0
- package/skills/ux-walker/references/triage-rubric.md +55 -0
- package/skills/ux-walker/references/ux-audit-rubric.md +174 -0
- package/skills/ux-walker/references/visual-inspection.md +92 -0
- package/skills/ux-walker/templates/latest-report-template.md +139 -0
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ux-walker
|
|
3
|
+
description: Walk a UX story catalog (docs/ux-paths/catalog.md) through a real browser one story at a time, checking each journey for correctness, visual quality and UX. Looks at screenshots with look_at_image, measures alignment, spacing and wrapping with a geometry audit, and logs flow friction. Fixes small issues and writes up larger ones.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# UX Walker
|
|
7
|
+
|
|
8
|
+
Walk each story in the catalog through a real browser. For every story, check that the
|
|
9
|
+
journey works, that the screens look right, and that the path is as short and clear as
|
|
10
|
+
it should be. Fix small problems on the spot. Write up larger ones.
|
|
11
|
+
|
|
12
|
+
This skill runs on your default model. Do not switch to a more expensive model. You
|
|
13
|
+
cannot see images directly: judge screenshots with the `look_at_image` tool (a cheap
|
|
14
|
+
vision model), and use DOM measurements for anything that can be measured.
|
|
15
|
+
|
|
16
|
+
Everything runs in one agent, in order. Walk one story, write its files, keep a
|
|
17
|
+
one-line summary in your head, then start the next. Do not try to hold several stories
|
|
18
|
+
in context. After a context reset, resume from the files in `docs/ux-walker/`.
|
|
19
|
+
|
|
20
|
+
## When to use
|
|
21
|
+
|
|
22
|
+
"walk the stories", "test the ux paths", "ux walker", "verify user journeys", "qa the
|
|
23
|
+
user flows". Needs a catalog at `docs/ux-paths/catalog.md` (made by the ux-paths skill).
|
|
24
|
+
|
|
25
|
+
Options the user may give: a URL, `--full` (re-walk everything), `--focus <topic>`
|
|
26
|
+
(only that topic), `--session <name>` (reuse a browser session, keeps login). With no
|
|
27
|
+
arguments, detect the URL and start. Ask only if the app needs a login and you have no
|
|
28
|
+
test credentials.
|
|
29
|
+
|
|
30
|
+
`$SKILL_DIR` below means the folder that contains this SKILL.md.
|
|
31
|
+
|
|
32
|
+
## Output
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
docs/ux-walker/
|
|
36
|
+
run-history.json state across runs
|
|
37
|
+
walk-plan.json plan for the current run
|
|
38
|
+
latest-report.md final report
|
|
39
|
+
issues-filed.md every issue written up
|
|
40
|
+
issues/<finding-id>.md issue files when gh is not available
|
|
41
|
+
shots/STORY-NNN/ screenshots (must stay inside the project folder)
|
|
42
|
+
stories/STORY-NNN/walk-report.md what happened at each step
|
|
43
|
+
stories/STORY-NNN/findings.json findings for the story
|
|
44
|
+
fixes/<finding-id>.md one note per quick fix
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Screenshots must be saved inside the project folder, or look_at_image refuses them.
|
|
48
|
+
|
|
49
|
+
## Step 0: Preflight
|
|
50
|
+
|
|
51
|
+
1. **Browser tool.** `command -v agent-browser`. If missing, use `npx -y agent-browser`
|
|
52
|
+
everywhere below instead. On first use run `agent-browser install` (or
|
|
53
|
+
`npx -y agent-browser install`) once. Command patterns: `references/action-patterns.md`.
|
|
54
|
+
2. **URL.** `curl -s -o /dev/null -w "%{http_code}" <url>`. If nothing answers, find the
|
|
55
|
+
dev command in package.json (or the README), start it in the background with a log
|
|
56
|
+
and a saved PID (`nohup <cmd> > docs/ux-walker/dev.log 2>&1 & echo $! > docs/ux-walker/dev.pid`),
|
|
57
|
+
pick a free port, wait for it once, and stop only that PID at the end. If you saved browser login state, delete `"${TMPDIR:-/tmp}/free-pi-ux-browser-state.json"` too.
|
|
58
|
+
3. **Catalog.** If `docs/ux-paths/catalog.md` is missing, stop and tell the user to run
|
|
59
|
+
the ux-paths skill first.
|
|
60
|
+
4. **Folders.** `mkdir -p docs/ux-walker/stories docs/ux-walker/shots docs/ux-walker/fixes`. Before a story's
|
|
61
|
+
first screenshot, also run `mkdir -p docs/ux-walker/shots/STORY-NNN` (agent-browser does not create it).
|
|
62
|
+
5. **Run history.** Load `docs/ux-walker/run-history.json`, or start with
|
|
63
|
+
`{"runs": [], "stories": {}}`. Each story entry: `last_walked`, `status`
|
|
64
|
+
(pass or fail), `findings_count`, `source_files_hash`, `fixes_merged_since`.
|
|
65
|
+
6. **Session.** Use `S=ux-walker-<domain>` (or the user's `--session`). Open the app:
|
|
66
|
+
`agent-browser --session $S open <url>` then `agent-browser --session $S wait --load networkidle`
|
|
67
|
+
(for apps with live connections, wait for a known element instead).
|
|
68
|
+
7. **Version check (optional).** `curl -s <url>/__version` or `<url>/version.json`. If it
|
|
69
|
+
returns a git SHA that differs from `git rev-parse --short HEAD`, note that you may
|
|
70
|
+
be testing an older build and continue.
|
|
71
|
+
|
|
72
|
+
## Step 1: Plan the walk
|
|
73
|
+
|
|
74
|
+
Read the catalog once. Write `docs/ux-walker/walk-plan.json` with one entry per story:
|
|
75
|
+
`{id, action, reason}`. Decide each action:
|
|
76
|
+
|
|
77
|
+
- `--full`: all stories are `walk`. `--focus topic`: only matching stories.
|
|
78
|
+
- Never walked: `walk`.
|
|
79
|
+
- Passed before and relevant source files unchanged since (`git log --since` on the
|
|
80
|
+
files the story touches, or compare `source_files_hash`): `skip`.
|
|
81
|
+
- Passed before but source changed: `re-verify`.
|
|
82
|
+
- Failed before and fixes made since: `re-verify`. Failed with no fixes: `walk`.
|
|
83
|
+
|
|
84
|
+
Tell the user the counts (walk, re-verify, skip), then start.
|
|
85
|
+
|
|
86
|
+
## Step 2: Walk the stories, one at a time
|
|
87
|
+
|
|
88
|
+
Read `references/ux-audit-rubric.md` and `references/visual-inspection.md` once before
|
|
89
|
+
the first story. For each story in the plan, in order:
|
|
90
|
+
|
|
91
|
+
### 2a. Walk
|
|
92
|
+
|
|
93
|
+
A story in the catalog has: Type, Topic, Persona, Goal, Preconditions, Steps,
|
|
94
|
+
Variations, Edge Cases, and sometimes an Ideal path. Use these fields as written.
|
|
95
|
+
|
|
96
|
+
For each step:
|
|
97
|
+
1. `agent-browser --session $S snapshot -i`, find the target by text or role, act
|
|
98
|
+
(`click @e3`, `fill @e2 "..."`, `open <url>`). See `references/action-patterns.md`.
|
|
99
|
+
2. Screenshot into `docs/ux-walker/shots/STORY-NNN/step-N.png`.
|
|
100
|
+
3. Check the step's expected result from the snapshot or `get text` / `get url`.
|
|
101
|
+
4. At each **distinct page state** (a new page or a major layout change, not every
|
|
102
|
+
click): run the geometry audit, then make one look_at_image call (below).
|
|
103
|
+
5. Check `agent-browser --session $S errors` now and then. Console errors and failed
|
|
104
|
+
requests often explain visible problems.
|
|
105
|
+
|
|
106
|
+
**Geometry audit** (measure first):
|
|
107
|
+
```bash
|
|
108
|
+
agent-browser --session $S eval --stdin < "$SKILL_DIR/references/geometry-audit.js"
|
|
109
|
+
```
|
|
110
|
+
It reports uneven sibling rows, overflow spills, wrapped controls and page horizontal
|
|
111
|
+
overflow. Confirm each hit before logging it.
|
|
112
|
+
|
|
113
|
+
**look_at_image** (one call per distinct page state, one specific question):
|
|
114
|
+
```
|
|
115
|
+
look_at_image(path="docs/ux-walker/shots/STORY-007/step-3.png",
|
|
116
|
+
question="<the look-pass question from references/visual-inspection.md, trimmed to this screen>")
|
|
117
|
+
```
|
|
118
|
+
Each call uses part of the user's daily allowance. Do not call it for every step, do
|
|
119
|
+
not ask about the same image twice, and do not use it to measure. The answer comes
|
|
120
|
+
from another model and can be wrong: check any layout claim with `get box` or the
|
|
121
|
+
geometry audit before you log it.
|
|
122
|
+
|
|
123
|
+
**Responsive spot-check**, once per story at its main screen (skip for desktop-only
|
|
124
|
+
apps): `set viewport 390 844`, screenshot, run the geometry audit, `set viewport 1280 800`.
|
|
125
|
+
Only spend a look_at_image call if the audit reports something or the page looks odd.
|
|
126
|
+
|
|
127
|
+
**Audit the page state** against `references/ux-audit-rubric.md`: simplicity,
|
|
128
|
+
progressive disclosure, layout, visual correctness and consistency, hierarchy (one
|
|
129
|
+
clear primary action, nothing said twice), typography, feedback, error states, text
|
|
130
|
+
fit, accessibility basics. Ask "what could be removed without losing function?"
|
|
131
|
+
|
|
132
|
+
**Flow log** (write it as the last section of walk-report.md):
|
|
133
|
+
- Steps the story specified versus steps you actually needed. If the catalog has an
|
|
134
|
+
Ideal path and you needed more steps, log a `flow` finding naming the friction.
|
|
135
|
+
- Each moment the persona would hesitate (control not found in the first snapshot,
|
|
136
|
+
ambiguous label, unexpected navigation): a discoverability finding.
|
|
137
|
+
- Data the user re-enters that the app already knows: a `flow` finding.
|
|
138
|
+
- Information or controls shown on more than one screen: note it in the log.
|
|
139
|
+
|
|
140
|
+
If a step fails (element missing, unexpected state): screenshot, record the failure,
|
|
141
|
+
try to recover (back, reload), continue the remaining steps, and mark the story `fail`.
|
|
142
|
+
|
|
143
|
+
For an interaction bug that a still image cannot show, record a short video:
|
|
144
|
+
`record start docs/ux-walker/shots/STORY-NNN/finding-N.webm`, repeat the steps with
|
|
145
|
+
`wait 1000` between them, `record stop`. For a static bug one screenshot is enough.
|
|
146
|
+
|
|
147
|
+
### 2b. Write the files now
|
|
148
|
+
|
|
149
|
+
Before starting the next story, write:
|
|
150
|
+
- `stories/STORY-NNN/walk-report.md`: for each distinct screen, one sentence on what the
|
|
151
|
+
screenshot shows plus the geometry result ("clean" or the hits); end with the flow log.
|
|
152
|
+
- `stories/STORY-NNN/findings.json`: array of objects:
|
|
153
|
+
```json
|
|
154
|
+
{"id": "F-007-001", "story_id": "STORY-007",
|
|
155
|
+
"severity": "critical|high|medium|low|suggestion",
|
|
156
|
+
"category": "simplicity|disclosure|layout|visual|consistency|hierarchy|flow|happy-path|a11y|error-handling",
|
|
157
|
+
"criterion": "which check failed", "score": "warn|fail",
|
|
158
|
+
"description": "", "expected": "", "actual": "",
|
|
159
|
+
"screenshot": "shots/STORY-007/finding-1.png",
|
|
160
|
+
"suggested_fix": "or null", "files_likely_involved": ["src/Foo.tsx"]}
|
|
161
|
+
```
|
|
162
|
+
- Update the story's entry in `run-history.json`.
|
|
163
|
+
|
|
164
|
+
Every finding needs at least a screenshot path, and a measurement when the problem is
|
|
165
|
+
visual ("left edges differ by 7px"). Stories are a script, not a limit: log anything
|
|
166
|
+
else you notice. Do not read source code while walking. Read it only when you fix.
|
|
167
|
+
|
|
168
|
+
Keep only a one-line summary of the story in context ("STORY-007 fail, 3 findings:
|
|
169
|
+
1 high, 2 low"), then triage that story's findings and move on.
|
|
170
|
+
|
|
171
|
+
### 2c. Triage
|
|
172
|
+
|
|
173
|
+
Use `references/triage-rubric.md`. A finding is a **quick fix** only if it touches 2 or
|
|
174
|
+
fewer files, has an obvious fix, is low risk, and is medium severity or lower. Critical
|
|
175
|
+
and high findings, anything needing design thought, and anything touching 3 or more
|
|
176
|
+
files are written up as issues. Suggestions are only listed in the report. At most 10
|
|
177
|
+
quick fixes per run.
|
|
178
|
+
|
|
179
|
+
### 2d. Fix (one at a time)
|
|
180
|
+
|
|
181
|
+
For each quick fix, in order:
|
|
182
|
+
1. Read the relevant source files. Make the smallest change that resolves the finding.
|
|
183
|
+
Only edit files inside the project folder; if the page is served from somewhere else, write the
|
|
184
|
+
fix up as an issue instead.
|
|
185
|
+
No refactoring, no nearby "improvements".
|
|
186
|
+
2. Run the project's build, type check or the nearest test (look in package.json).
|
|
187
|
+
3. Commit only the files you changed, with `fix(ux): <finding-id> <short description>`.
|
|
188
|
+
Never `git add -A`. Work on the current branch unless the user says otherwise; if it
|
|
189
|
+
is the default branch, create a branch first. Do not push.
|
|
190
|
+
4. Write `docs/ux-walker/fixes/<finding-id>.md`: what was wrong, what changed, build result.
|
|
191
|
+
5. Re-check the fix in the browser (reload, repeat the step, run the geometry audit,
|
|
192
|
+
take a new screenshot). If it persists, revert your change and write it up as an issue.
|
|
193
|
+
|
|
194
|
+
If a fix breaks the build and you cannot repair it quickly, revert it and write an issue.
|
|
195
|
+
|
|
196
|
+
### 2e. Write up larger issues
|
|
197
|
+
|
|
198
|
+
For each finding that is not a quick fix, use `references/issue-template.md`.
|
|
199
|
+
|
|
200
|
+
- If `command -v gh` succeeds and `gh auth status` passes: `gh issue create` with the
|
|
201
|
+
filled template (`--label ux-walker`; add other labels only if they exist).
|
|
202
|
+
- Otherwise save the filled template to `docs/ux-walker/issues/<finding-id>.md`.
|
|
203
|
+
|
|
204
|
+
Add a row to `docs/ux-walker/issues-filed.md`: issue (number or file), story, severity,
|
|
205
|
+
title, URL or path.
|
|
206
|
+
|
|
207
|
+
## Step 3: Re-walk fixed stories
|
|
208
|
+
|
|
209
|
+
After all stories are done, re-walk only the steps that had fixed findings, one story at
|
|
210
|
+
a time, with a fresh screenshot and audit. Mark the story `pass` if all findings are
|
|
211
|
+
resolved, otherwise `fail` and note what remains. Update `run-history.json` with the
|
|
212
|
+
run totals (stories walked, skipped, re-verified, findings, fixes, issues, passed, failed).
|
|
213
|
+
|
|
214
|
+
## Step 4: Report
|
|
215
|
+
|
|
216
|
+
Read the story files one at a time and build `docs/ux-walker/latest-report.md` from
|
|
217
|
+
`templates/latest-report-template.md`. Include:
|
|
218
|
+
|
|
219
|
+
1. Run metadata (date, URL, session, counts).
|
|
220
|
+
2. Findings by severity and by category.
|
|
221
|
+
3. Quick fixes applied (finding, files, verified or not).
|
|
222
|
+
4. Issues filed or saved (with paths or URLs).
|
|
223
|
+
5. UX audit summary: patterns across stories and systemic issues. The same audit defect
|
|
224
|
+
on several screens is one systemic finding.
|
|
225
|
+
6. Flow friction table (story, actual versus ideal steps, hesitations) and information
|
|
226
|
+
shown in more than one place. If flow or redundancy shows up in 3 or more stories,
|
|
227
|
+
recommend running the ux-flow skill.
|
|
228
|
+
7. Top 5 recommendations.
|
|
229
|
+
8. Stories still failing, with reasons.
|
|
230
|
+
|
|
231
|
+
Finish with a short summary to the user: stories walked, pass and fail counts, fixes
|
|
232
|
+
made (with commit SHAs), issues written, and the path to the report. State plainly
|
|
233
|
+
what you did not verify.
|
|
234
|
+
|
|
235
|
+
## Error handling
|
|
236
|
+
|
|
237
|
+
| Situation | Action |
|
|
238
|
+
|-----------|--------|
|
|
239
|
+
| agent-browser cannot connect | Retry once. Run `agent-browser install` if the browser is missing. If it still fails, tell the user. |
|
|
240
|
+
| Step fails | Screenshot, recover, continue, mark the story `fail`. |
|
|
241
|
+
| look_at_image returns an error (daily allowance, rate limit) | Do not retry in a loop. Rely on the geometry audit and the snapshot for the rest of the run, say so in the report, and tell the user. |
|
|
242
|
+
| Fix breaks the build | Revert it and write an issue. |
|
|
243
|
+
| Catalog missing | Stop. Ask the user to run the ux-paths skill. |
|
|
244
|
+
| Nothing to walk | Report that all stories pass with no source changes. Suggest `--full`. |
|
|
245
|
+
|
|
246
|
+
## Rules
|
|
247
|
+
|
|
248
|
+
- Never delete screenshots, videos or reports during a run.
|
|
249
|
+
- Use test accounts and test data only. Do not click destructive actions against real data.
|
|
250
|
+
- Write each story's files before starting the next story.
|
|
251
|
+
- Do not push, and do not merge to the default branch.
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Action patterns: story step to agent-browser command
|
|
2
|
+
|
|
3
|
+
All commands run through bash. Use `agent-browser --session $S <command>`.
|
|
4
|
+
Run `agent-browser <command> --help` if unsure; do not guess flags.
|
|
5
|
+
|
|
6
|
+
## Core loop
|
|
7
|
+
|
|
8
|
+
1. `snapshot -i` lists interactive elements with refs such as `@e3`.
|
|
9
|
+
2. Act on a ref (or a CSS selector).
|
|
10
|
+
3. Take a screenshot into the project folder.
|
|
11
|
+
4. Verify the expected result (re-run `snapshot -i`, or `get text`, `get url`).
|
|
12
|
+
|
|
13
|
+
Refs go stale after navigation or large page changes. Take a fresh snapshot then.
|
|
14
|
+
|
|
15
|
+
## Actions
|
|
16
|
+
|
|
17
|
+
| Story step | Command |
|
|
18
|
+
|---|---|
|
|
19
|
+
| Go to a URL | `agent-browser --session $S open <url>` |
|
|
20
|
+
| Back / forward / reload | `back`, `forward`, `reload` |
|
|
21
|
+
| Click a ref | `click @e3` |
|
|
22
|
+
| Click by visible text (no snapshot yet) | `find text "Sign in" click` |
|
|
23
|
+
| Click by role and name | `find role button --name "Save" click` |
|
|
24
|
+
| Type character by character | `type @e2 "hello"` |
|
|
25
|
+
| Replace a field value | `fill @e2 "hello"` |
|
|
26
|
+
| Fill by label | `find label "Email" fill "a@b.test"` |
|
|
27
|
+
| Choose a dropdown option | `select @e4 "Option A"` |
|
|
28
|
+
| Check / uncheck | `check @e5`, `uncheck @e5` |
|
|
29
|
+
| Press a key | `press Enter`, `press Escape`, `press Tab` |
|
|
30
|
+
| Hover | `hover @e6` |
|
|
31
|
+
| Scroll | `scroll down 400`, `scrollintoview @e7` |
|
|
32
|
+
| Wait for page | `wait --load networkidle` (live apps with websockets never go idle; use the next line) |
|
|
33
|
+
| Wait for text or element | `wait --text "Saved"`, `wait "#results"`, `wait 800` (ms) |
|
|
34
|
+
| Current URL / title | `get url`, `get title` |
|
|
35
|
+
| Element text | `get text @e3` |
|
|
36
|
+
| Element size and position | `get box <selector>` |
|
|
37
|
+
| Computed styles | `get styles <selector>` |
|
|
38
|
+
| Console errors | `errors`, `console` |
|
|
39
|
+
| Screenshot (viewport) | `screenshot docs/ux-walker/shots/<story>/step-1.png` |
|
|
40
|
+
| Screenshot (whole page) | `screenshot --full <path>` |
|
|
41
|
+
| Numbered labels on controls | `screenshot --annotate <path>` |
|
|
42
|
+
| Narrow / wide viewport | `set viewport 390 844`, `set viewport 1280 800` |
|
|
43
|
+
| Dark mode | `set media dark`, `set media light` |
|
|
44
|
+
| Save / restore login | `state save "${TMPDIR:-/tmp}/free-pi-ux-browser-state.json"`, `state load "${TMPDIR:-/tmp}/free-pi-ux-browser-state.json"` (kept outside the project because it holds cookies; never commit it; delete it at the end of the run) |
|
|
45
|
+
| Video of an interaction | `record start docs/ux-walker/shots/<story>/f1.webm`, act with `wait 1000` between steps, `record stop` |
|
|
46
|
+
|
|
47
|
+
Several commands can go in one bash call, joined with `&&`.
|
|
48
|
+
|
|
49
|
+
## Run the audit script
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
agent-browser --session $S eval --stdin < "$SKILL_DIR/references/geometry-audit.js"
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
`$SKILL_DIR` is the folder that contains this skill's SKILL.md.
|
|
56
|
+
|
|
57
|
+
## Common flows
|
|
58
|
+
|
|
59
|
+
Login: `snapshot -i`, `fill @e1 "<user>"`, `fill @e2 "<password>"`, `click @e3`,
|
|
60
|
+
`wait --load networkidle`, screenshot, then `state save` to the path above. Use only test accounts that
|
|
61
|
+
the project provides. Never type real credentials from the user's environment.
|
|
62
|
+
|
|
63
|
+
Modal: click the trigger, `wait 500`, `snapshot -i` (the modal is now in the tree),
|
|
64
|
+
screenshot, act, `snapshot -i` again to confirm it closed.
|
|
65
|
+
|
|
66
|
+
Form: `snapshot -i`, `fill` each field by ref, submit, `wait --text "<success text>"`.
|
|
67
|
+
|
|
68
|
+
Drag: `drag @e1 @e2`, then screenshot.
|
|
69
|
+
|
|
70
|
+
## Pacing and recovery
|
|
71
|
+
|
|
72
|
+
- `wait 500` after clicks that animate; `wait 1000` after navigation or submit.
|
|
73
|
+
- If an action fails: screenshot, `snapshot -i`, then try once more (scroll into
|
|
74
|
+
view, wait, fresh snapshot). If it fails twice, log the failure and go to the next step.
|
|
75
|
+
- If `agent-browser` cannot start, run `npx -y agent-browser install` once and retry.
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// Geometry audit — run via: agent-browser --session {S} eval "$(cat geometry-audit.js)"
|
|
2
|
+
// Returns JSON of measurable layout defects. Numbers beat eyeballs for evenness;
|
|
3
|
+
// use the screenshot to judge whether a reported violation actually matters.
|
|
4
|
+
(() => {
|
|
5
|
+
const sig = (e) => {
|
|
6
|
+
let s = e.tagName.toLowerCase();
|
|
7
|
+
if (e.id) s += '#' + e.id;
|
|
8
|
+
else if (typeof e.className === 'string' && e.className.trim())
|
|
9
|
+
s += '.' + e.className.trim().split(/\s+/).slice(0, 2).join('.');
|
|
10
|
+
const t = (e.textContent || '').trim().replace(/\s+/g, ' ').slice(0, 30);
|
|
11
|
+
return t ? s + ' "' + t + '"' : s;
|
|
12
|
+
};
|
|
13
|
+
const vis = (e) => {
|
|
14
|
+
const r = e.getBoundingClientRect();
|
|
15
|
+
if (r.width < 1 || r.height < 1) return false;
|
|
16
|
+
const cs = getComputedStyle(e);
|
|
17
|
+
return cs.visibility !== 'hidden' && cs.display !== 'none';
|
|
18
|
+
};
|
|
19
|
+
const firstClass = (e) =>
|
|
20
|
+
typeof e.className === 'string' ? (e.className.trim().split(/\s+/)[0] || '') : '';
|
|
21
|
+
|
|
22
|
+
const out = {
|
|
23
|
+
pageOverflowX: Math.max(0, document.documentElement.scrollWidth - window.innerWidth),
|
|
24
|
+
unevenRows: [], // similar siblings in one visual row with different shapes/gaps
|
|
25
|
+
overflowSpills: [], // content escaping its container
|
|
26
|
+
wrappedControls: [], // short button/tab/chip labels forced onto 2+ lines
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// 1. Sibling uniformity: flex-row/grid containers whose children are structurally
|
|
30
|
+
// similar (same tag + first class) should share height, width, gap, and top edge.
|
|
31
|
+
for (const p of document.querySelectorAll('body *')) {
|
|
32
|
+
const cs = getComputedStyle(p);
|
|
33
|
+
const flexRow = cs.display.includes('flex') && cs.flexDirection.startsWith('row');
|
|
34
|
+
const grid = cs.display.includes('grid');
|
|
35
|
+
if (!flexRow && !grid) continue;
|
|
36
|
+
const kids = [...p.children].filter(vis);
|
|
37
|
+
if (kids.length < 2 || kids.length > 16) continue;
|
|
38
|
+
if (!kids.every((k) => k.tagName === kids[0].tagName && firstClass(k) === firstClass(kids[0]))) continue;
|
|
39
|
+
const rects = kids.map((k) => k.getBoundingClientRect());
|
|
40
|
+
const topDrift = Math.max(...rects.map((r) => r.top)) - Math.min(...rects.map((r) => r.top));
|
|
41
|
+
if (topDrift > 24) continue; // wrapped onto multiple rows — not one visual row
|
|
42
|
+
const hs = rects.map((r) => Math.round(r.height));
|
|
43
|
+
const ws = rects.map((r) => Math.round(r.width));
|
|
44
|
+
const sorted = [...rects].sort((a, b) => a.left - b.left);
|
|
45
|
+
const gaps = [];
|
|
46
|
+
for (let i = 1; i < sorted.length; i++) gaps.push(Math.round(sorted[i].left - sorted[i - 1].right));
|
|
47
|
+
const issue = {};
|
|
48
|
+
if (Math.max(...hs) - Math.min(...hs) > 8) issue.heights = hs;
|
|
49
|
+
if (flexRow && Math.max(...ws) - Math.min(...ws) > 8) issue.widths = ws;
|
|
50
|
+
if (gaps.length > 1 && Math.max(...gaps) - Math.min(...gaps) > 4) issue.gaps = gaps;
|
|
51
|
+
if (topDrift > 3) issue.topDriftPx = Math.round(topDrift);
|
|
52
|
+
if (Object.keys(issue).length)
|
|
53
|
+
out.unevenRows.push({ container: sig(p), children: kids.length, ...issue });
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// 2. Overflow: element content wider than its box while overflow-x is visible.
|
|
57
|
+
for (const e of document.querySelectorAll('body *')) {
|
|
58
|
+
if (!vis(e) || e.clientWidth < 24) continue;
|
|
59
|
+
if (!getComputedStyle(e).overflowX.includes('visible')) continue;
|
|
60
|
+
if (e.scrollWidth > e.clientWidth + 4)
|
|
61
|
+
out.overflowSpills.push({ el: sig(e), spillPx: e.scrollWidth - e.clientWidth });
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// 3. Wrapped controls: a short label on a block-ish control taking 2+ lines
|
|
65
|
+
// means the container is too narrow or the label too long for the layout.
|
|
66
|
+
for (const b of document.querySelectorAll('button, [role="button"], a, summary, [class*="tab"], [class*="chip"], [class*="badge"]')) {
|
|
67
|
+
if (!vis(b)) continue;
|
|
68
|
+
const cs = getComputedStyle(b);
|
|
69
|
+
if (cs.display === 'inline') continue; // prose links legitimately wrap
|
|
70
|
+
if (b.querySelector('br, svg, img')) continue;
|
|
71
|
+
const label = (b.textContent || '').trim();
|
|
72
|
+
if (!label || label.length > 40) continue;
|
|
73
|
+
const lh = parseFloat(cs.lineHeight) || parseFloat(cs.fontSize) * 1.4;
|
|
74
|
+
const contentH = b.clientHeight - parseFloat(cs.paddingTop) - parseFloat(cs.paddingBottom);
|
|
75
|
+
if (contentH > lh * 1.8) out.wrappedControls.push(sig(b));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
for (const k of ['unevenRows', 'overflowSpills', 'wrappedControls']) {
|
|
79
|
+
if (out[k].length > 12) { out[k] = out[k].slice(0, 12); out[k + 'Truncated'] = true; }
|
|
80
|
+
}
|
|
81
|
+
return JSON.stringify(out);
|
|
82
|
+
})();
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# GitHub Issue Template — UX Walker Findings
|
|
2
|
+
|
|
3
|
+
Use this for findings the triage rubric sends to an issue. File with `gh issue create` only if `gh` is installed and authenticated; otherwise save the filled template to `docs/ux-walker/issues/{FINDING_ID}.md`.
|
|
4
|
+
|
|
5
|
+
## Template
|
|
6
|
+
|
|
7
|
+
```markdown
|
|
8
|
+
## Context
|
|
9
|
+
|
|
10
|
+
Found by ux-walker during **STORY-{STORY_ID}: "{STORY_TITLE}"**
|
|
11
|
+
- **Run date**: {ISO_DATE}
|
|
12
|
+
- **Step**: Step {STEP_NUMBER} — "{STEP_DESCRIPTION}"
|
|
13
|
+
- **URL at time of finding**: {CURRENT_URL}
|
|
14
|
+
|
|
15
|
+
## Finding
|
|
16
|
+
|
|
17
|
+
**ID**: {FINDING_ID}
|
|
18
|
+
**Severity**: {SEVERITY}
|
|
19
|
+
**Category**: {CATEGORY}
|
|
20
|
+
**Rubric Criterion**: {CRITERION} ({SCORE})
|
|
21
|
+
|
|
22
|
+
### Description
|
|
23
|
+
{DETAILED_DESCRIPTION}
|
|
24
|
+
|
|
25
|
+
### Expected Behavior
|
|
26
|
+
{EXPECTED}
|
|
27
|
+
|
|
28
|
+
### Actual Behavior
|
|
29
|
+
{ACTUAL}
|
|
30
|
+
|
|
31
|
+
## Evidence
|
|
32
|
+
|
|
33
|
+
### Screenshot
|
|
34
|
+
<!-- Attach or reference the screenshot -->
|
|
35
|
+

|
|
36
|
+
|
|
37
|
+
### Page Snapshot (if relevant)
|
|
38
|
+
<details>
|
|
39
|
+
<summary>Accessibility tree at time of finding</summary>
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
{SNAPSHOT_EXCERPT}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
</details>
|
|
46
|
+
|
|
47
|
+
## Suggested Approach
|
|
48
|
+
|
|
49
|
+
{SUGGESTED_FIX_OR_APPROACH}
|
|
50
|
+
|
|
51
|
+
### Files Likely Involved
|
|
52
|
+
{FILES_LIST — bulleted list of file paths}
|
|
53
|
+
|
|
54
|
+
### Estimated Complexity
|
|
55
|
+
- **Files to change**: {FILE_COUNT}
|
|
56
|
+
- **Regression risk**: {LOW|MEDIUM|HIGH}
|
|
57
|
+
- **Design input needed**: {YES|NO}
|
|
58
|
+
|
|
59
|
+
## Related
|
|
60
|
+
|
|
61
|
+
- **Story**: STORY-{STORY_ID} in `docs/ux-paths/catalog.md`
|
|
62
|
+
- **Walk report**: `docs/ux-walker/stories/STORY-{STORY_ID}/walk-report.md`
|
|
63
|
+
- **Full findings**: `docs/ux-walker/stories/STORY-{STORY_ID}/findings.json`
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
Filed by ux-walker
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Usage — gh CLI Command
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
gh issue create \
|
|
73
|
+
--title "UX: {SHORT_DESCRIPTION}" \
|
|
74
|
+
--body "$(cat <<'EOF'
|
|
75
|
+
{FILLED_TEMPLATE}
|
|
76
|
+
EOF
|
|
77
|
+
)" \
|
|
78
|
+
--label "ux-walker"
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Field Reference
|
|
82
|
+
|
|
83
|
+
| Field | Source | Example |
|
|
84
|
+
|-------|--------|---------|
|
|
85
|
+
| `STORY_ID` | walk-plan.json | `STORY-014` |
|
|
86
|
+
| `STORY_TITLE` | catalog.md | `New user creates first workspace` |
|
|
87
|
+
| `ISO_DATE` | Current timestamp | `2026-03-20T14:30:00Z` |
|
|
88
|
+
| `STEP_NUMBER` | findings.json → step | `3` |
|
|
89
|
+
| `STEP_DESCRIPTION` | catalog.md step text | `Click "Create Workspace" button` |
|
|
90
|
+
| `CURRENT_URL` | agent-browser url output | `http://localhost:1420/workspaces` |
|
|
91
|
+
| `FINDING_ID` | findings.json → id | `F-014-003` |
|
|
92
|
+
| `SEVERITY` | findings.json → severity | `high` |
|
|
93
|
+
| `CATEGORY` | findings.json → category | `layout` |
|
|
94
|
+
| `CRITERION` | findings.json → criterion | `Viewport usage` |
|
|
95
|
+
| `SCORE` | findings.json → score | `fail` |
|
|
96
|
+
| `DETAILED_DESCRIPTION` | findings.json → description | Full narrative |
|
|
97
|
+
| `EXPECTED` | findings.json → expected | What should happen |
|
|
98
|
+
| `ACTUAL` | findings.json → actual | What actually happens |
|
|
99
|
+
| `SCREENSHOT_PATH` | findings.json → screenshot | Relative path |
|
|
100
|
+
| `SNAPSHOT_EXCERPT` | Saved snapshot output | Trimmed to relevant section |
|
|
101
|
+
| `SUGGESTED_FIX_OR_APPROACH` | findings.json → suggested_fix | Or "Needs design discussion" |
|
|
102
|
+
| `FILES_LIST` | findings.json → files_likely_involved | Bulleted paths |
|
|
103
|
+
| `FILE_COUNT` | Derived from files list | `4` |
|
|
104
|
+
|
|
105
|
+
## Notes
|
|
106
|
+
|
|
107
|
+
- Keep issue titles under 70 characters
|
|
108
|
+
- Title format: `UX: {verb} {what}` — e.g., "UX: simplify workspace creation form"
|
|
109
|
+
- If no suggested approach is obvious, write "Needs design discussion — the current implementation {description of problem}."
|
|
110
|
+
- Always include the screenshot — it's the most valuable part for async review
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Triage rubric: quick fix or written issue
|
|
2
|
+
|
|
3
|
+
Decide for each finding after a story is walked.
|
|
4
|
+
|
|
5
|
+
## Quick fix: ALL must be true
|
|
6
|
+
|
|
7
|
+
1. Touches 2 or fewer source files.
|
|
8
|
+
2. The fix is obvious (typo, CSS tweak, missing label, wrong color, spacing).
|
|
9
|
+
3. Low regression risk.
|
|
10
|
+
4. Can be done in under 15 minutes.
|
|
11
|
+
5. Severity is medium or lower.
|
|
12
|
+
|
|
13
|
+
Examples: typo in a button; padding off by a few pixels; missing label or aria-label;
|
|
14
|
+
text overflow in one component; missing hover style; sibling cards with uneven
|
|
15
|
+
heights (`align-items: stretch`); wrapped button label (`white-space: nowrap`);
|
|
16
|
+
uneven gaps (use `gap`); inconsistent border radius.
|
|
17
|
+
|
|
18
|
+
## Write an issue: ANY is true
|
|
19
|
+
|
|
20
|
+
- Touches 3 or more files.
|
|
21
|
+
- Needs design thought or changes a workflow or information structure.
|
|
22
|
+
- Could break other features.
|
|
23
|
+
- Severity is critical or high.
|
|
24
|
+
- Restructures components or changes state handling.
|
|
25
|
+
- Needs a feature that does not exist.
|
|
26
|
+
|
|
27
|
+
Examples: confusing navigation; a 15-field form that should be progressive; raw API
|
|
28
|
+
errors shown to users; missing loading states across the app; broken mobile layout;
|
|
29
|
+
no keyboard support.
|
|
30
|
+
|
|
31
|
+
## Overrides
|
|
32
|
+
|
|
33
|
+
- Critical findings are always written up, even if the fix looks easy.
|
|
34
|
+
- Suggestions are never fixed or filed. They go in the report only.
|
|
35
|
+
- At most 10 quick fixes per run. Further findings become issues (a sign of a
|
|
36
|
+
systemic problem).
|
|
37
|
+
|
|
38
|
+
## Checklist
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
1. Severity medium or lower? no -> issue
|
|
42
|
+
2. 2 files or fewer? no -> issue
|
|
43
|
+
3. Solution obvious? no -> issue
|
|
44
|
+
4. Low regression risk? no -> issue
|
|
45
|
+
5. Fewer than 10 quick fixes so far? no -> issue
|
|
46
|
+
All yes -> quick fix
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Where issues go
|
|
50
|
+
|
|
51
|
+
If `command -v gh` finds GitHub CLI and `gh auth status` succeeds, file with
|
|
52
|
+
`gh issue create` (see issue-template.md). Otherwise write each issue as a markdown
|
|
53
|
+
file in `docs/ux-walker/issues/<finding-id>.md` using the same template, and list them
|
|
54
|
+
in `docs/ux-walker/issues-filed.md`. Labels: `ux-walker` plus the severity; add other
|
|
55
|
+
labels only if they already exist in the repo.
|