start-vibing 4.4.6 → 4.4.8
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/cli.js +3 -1
- package/package.json +1 -1
- package/template/.claude/agents/research-query.md +11 -0
- package/template/.claude/agents/research-synthesize.md +8 -0
- package/template/.claude/agents/sd-fix.md +185 -166
- package/template/.claude/agents/sd-research.md +72 -51
- package/template/.claude/settings.json +0 -11
- package/template/.claude/skills/super-design/references/market-research-playbook.md +364 -143
- package/template/.claude/hooks/block-plugin-commits.sh +0 -54
package/dist/cli.js
CHANGED
|
@@ -1055,7 +1055,9 @@ var MANAGED_PATHS = [
|
|
|
1055
1055
|
".claude/settings.json",
|
|
1056
1056
|
".claude/settings.local.json",
|
|
1057
1057
|
".claude/CLAUDE.md",
|
|
1058
|
-
"CLAUDE.md"
|
|
1058
|
+
"CLAUDE.md",
|
|
1059
|
+
".playwright-mcp/",
|
|
1060
|
+
".playwright-mcp"
|
|
1059
1061
|
];
|
|
1060
1062
|
function isPathTracked(targetDir, path) {
|
|
1061
1063
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "start-vibing",
|
|
3
|
-
"version": "4.4.
|
|
3
|
+
"version": "4.4.8",
|
|
4
4
|
"description": "Setup Claude Code with 9 plugins, 6 community skills, and 8 MCP servers. Parallel install, auto-accept, superpowers + ralph-loop. e2e-audit 0.2.0 refactor (skill-only, no agents): SessionStart hook + slash command make the skill keyword-invokable (\"e2e audit\", \"roda o e2e\", \"integration test\", \"test coverage gaps\"). Source-first discovery via detect-stack, discover-routes (Next app/pages/Remix/SvelteKit/Nuxt/Astro), discover-api-surface (HTTP handlers, tRPC procedures, GraphQL, server actions, middleware auth), inventory-existing-tests (preserve prior corpus + sha256 drift hash), and detect-uncovered (branch-diff vs origin/main finds changes not covered by existing specs). Report-then-ask between mapping and Playwright run; post-run-feedback report before writing findings. SHOT+TRACE+ASSERT+SOURCE evidence quad per non-meta finding; meta rules (coverage-gap-*, uncovered-*, test-drift, stack-detect, post-run-feedback) exempt. verify-audit.sh enforces schema + quad. Generic (no project leakage). super-design 0.7.0 carries over.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -69,6 +69,17 @@ WebFetch — it's already structured.
|
|
|
69
69
|
|
|
70
70
|
For each fetched source, extract 1–8 atomic claims. Each claim:
|
|
71
71
|
|
|
72
|
+
**Quote-grep pre-validation (MANDATORY before append).** This step prevents the synthesize→verify→synthesize loop. Before writing a claim to `claims.jsonl`:
|
|
73
|
+
|
|
74
|
+
1. Take the `quote` you just extracted.
|
|
75
|
+
2. Run: `grep -F -- "<first ~80 chars of quote>" "$SESSION_DIR/snapshots/<n>.md"` (use `-F` for fixed-string, no regex; pipe through if quote contains special shell chars).
|
|
76
|
+
3. If grep returns 0 matches:
|
|
77
|
+
- Try shortening the quote to the longest contiguous substring of the ORIGINAL source text (no edits, no paraphrase, no normalization) that DOES grep — then update the claim's `quote` field to that substring.
|
|
78
|
+
- If even a 30-char contiguous substring won't grep, **DROP the claim** and log to `$SESSION_DIR/fetch-errors.log` as `quote_pregrep_miss`. The snapshot likely doesn't contain the assertion verbatim.
|
|
79
|
+
4. Only when grep hits ≥1 match do you append the claim to `claims.jsonl`.
|
|
80
|
+
|
|
81
|
+
This guarantees every quote in `claims.jsonl` is already verifiable. The synthesize agent must then copy quotes byte-for-byte (its hard rule #8) so verify passes on first run.
|
|
82
|
+
|
|
72
83
|
```jsonc
|
|
73
84
|
{
|
|
74
85
|
"id": "C-0042",
|
|
@@ -137,3 +137,11 @@ disagreement count, open-question count). Verify agent will run next.
|
|
|
137
137
|
5. **No emoji in output** (the project's English-only rule applies; respect markdown styling discipline).
|
|
138
138
|
6. **Freshness banner mandatory** — every doc declares its bucket and aging status in frontmatter.
|
|
139
139
|
7. **Hand off doc to research-verify** — don't return success until verify has greenlit.
|
|
140
|
+
8. **QUOTE FIELD IS OPAQUE — BYTES-IN, BYTES-OUT.** This is the contract that the verify gate enforces and the #1 cause of synthesize→verify→synthesize loops. When you render a finding's evidence block, the `quote` value MUST be copied byte-for-byte from `claims.jsonl`. Forbidden transformations:
|
|
141
|
+
- Do NOT "clean up" punctuation, smart quotes (`"` `"` `'` `'`), em/en dashes, ellipses (`…` vs `...`), or whitespace.
|
|
142
|
+
- Do NOT trim, truncate, splice, or join lines.
|
|
143
|
+
- Do NOT translate, paraphrase, or correct typos — even obvious ones.
|
|
144
|
+
- Do NOT add or remove leading/trailing whitespace, markdown escapes, or backticks.
|
|
145
|
+
- If the quote contains characters that break markdown rendering (e.g. backticks, pipes inside tables), wrap the whole quote in a fenced block — do not edit the characters.
|
|
146
|
+
- If a quote is too long for narrative flow, do NOT shorten it by paraphrasing. Either: (a) keep it full, or (b) pick a shorter contiguous substring of the ORIGINAL bytes and use that instead — never an edited version.
|
|
147
|
+
- The literal string you write between the blockquote markers MUST be greppable in `snapshots/<n>.md` for that source. If you suspect a quote won't grep, drop the claim rather than edit the quote.
|
|
@@ -1,30 +1,30 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: sd-fix
|
|
3
|
-
description: Applies surgical fixes for super-design audit findings. Invoked when user explicitly asks for fixes after audit. Classifies risk, applies templates inline (a11y A1-A15, design V1-V8, ux U1-U10, perf P1-P10, mobile M1-M15, design-skill DSC-1 advisory),
|
|
3
|
+
description: Applies surgical fixes for super-design audit findings. Invoked when user explicitly asks for fixes after audit. Classifies risk, applies templates inline (a11y A1-A15, design V1-V8, ux U1-U10, perf P1-P10, mobile M1-M15, design-skill DSC-1 advisory), STAGES changes per fix with finding IDs (NEVER runs `git commit`/`git add -A`/`git push` — committing is delegated to commit-manager or the user's `/commit` flow), runs two-stage verify (technical + semantic), captures before/after screenshots via Playwright MCP, emits fix-report.md with visual diff, auto-rollback on failure.
|
|
4
4
|
tools:
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
5
|
+
- Read
|
|
6
|
+
- Edit
|
|
7
|
+
- MultiEdit
|
|
8
|
+
- Write
|
|
9
|
+
- Glob
|
|
10
|
+
- Grep
|
|
11
|
+
- Bash
|
|
12
|
+
- Task
|
|
13
|
+
- mcp__playwright__browser_navigate
|
|
14
|
+
- mcp__playwright__browser_navigate_back
|
|
15
|
+
- mcp__playwright__browser_resize
|
|
16
|
+
- mcp__playwright__browser_snapshot
|
|
17
|
+
- mcp__playwright__browser_take_screenshot
|
|
18
|
+
- mcp__playwright__browser_evaluate
|
|
19
|
+
- mcp__playwright__browser_click
|
|
20
|
+
- mcp__playwright__browser_wait_for
|
|
21
|
+
- mcp__playwright__browser_console_messages
|
|
22
|
+
- mcp__playwright__browser_install
|
|
23
|
+
- mcp__playwright__browser_close
|
|
24
24
|
model: sonnet
|
|
25
25
|
color: green
|
|
26
26
|
mcpServers:
|
|
27
|
-
|
|
27
|
+
- playwright
|
|
28
28
|
---
|
|
29
29
|
|
|
30
30
|
You are sd-fix — the unified fix agent. You apply templates for all four categories (a11y / design / ux / perf) inline, dispatching only to verify agents. You never auto-apply risk ≥ MEDIUM.
|
|
@@ -32,10 +32,11 @@ You are sd-fix — the unified fix agent. You apply templates for all four categ
|
|
|
32
32
|
# Preflight — always run
|
|
33
33
|
|
|
34
34
|
Read in order:
|
|
35
|
+
|
|
35
36
|
1. `.claude/skills/super-design/references/fix-agent-playbook.md`
|
|
36
37
|
2. `.claude/skills/mobile-app-patterns/SKILL.md` (M-template source — code snippets come from here)
|
|
37
38
|
3. `.claude/skills/super-design/references/design-skills-catalog.md` (DSC-1 advisory selection)
|
|
38
|
-
4. `.claude/skills/super-design/references/design-intelligence-rubric.md` (design-intelligence
|
|
39
|
+
4. `.claude/skills/super-design/references/design-intelligence-rubric.md` (design-intelligence-\* finding context)
|
|
39
40
|
|
|
40
41
|
Then:
|
|
41
42
|
|
|
@@ -59,8 +60,8 @@ git rev-parse HEAD > ".super-design/sessions/$SESSION_ID/base-sha"
|
|
|
59
60
|
- `.super-design/sessions/<id>/fix-results.json` (append-only)
|
|
60
61
|
- `.super-design/sessions/<id>/screens/F-NNNN_after_full.png` — after-fix full-page screenshot per applied finding
|
|
61
62
|
- `.super-design/sessions/<id>/screens/F-NNNN_after_element.png` — after-fix element-cropped screenshot per applied finding
|
|
62
|
-
-
|
|
63
|
-
- `docs/super-design/sessions/<session-id>/fix-report.md` — self-contained visual diff doc with per-finding before/after images, file diffs, verification, commit SHA
|
|
63
|
+
- Working-tree edits on the active branch, one logical fix at a time, **left staged but UNCOMMITTED** (commit-manager or `/commit` decides when to commit)
|
|
64
|
+
- `docs/super-design/sessions/<session-id>/fix-report.md` — self-contained visual diff doc with per-finding before/after images, file diffs, verification, and the staged-diff SHA (NOT a commit SHA)
|
|
64
65
|
- `docs/super-design/fix-history.md` appended (index of sessions with link to fix-report.md)
|
|
65
66
|
- Skipped HIGH → GitHub issues via `gh`
|
|
66
67
|
|
|
@@ -76,54 +77,62 @@ For each finding in findings.json, in order:
|
|
|
76
77
|
|
|
77
78
|
4. **Apply** via Edit (single) or MultiEdit (multiple in same file). NEVER Write unless creating net-new file (e.g., new EmptyState component).
|
|
78
79
|
|
|
79
|
-
5. **Verify** — spawn `sd-fix-verify-technical` via Task. On pass, spawn `sd-fix-verify-semantic` via Task. Only if BOTH pass → proceed to capture-after (5.5). Either fails → `git reset --hard
|
|
80
|
+
5. **Verify** — spawn `sd-fix-verify-technical` via Task. On pass, spawn `sd-fix-verify-semantic` via Task. Only if BOTH pass → proceed to capture-after (5.5). Either fails → roll back the working-tree changes from THIS fix only via `git restore --source=HEAD --staged --worktree -- <finding.files_affected>` (NEVER `git reset --hard`, NEVER touch other staged work), mark finding failed with rolled_back=true, continue.
|
|
80
81
|
|
|
81
82
|
5.5. **Capture after state** (mandatory for every applied finding — this is how the before/after report is built):
|
|
82
83
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
84
|
+
a. Ensure the app is reachable. If the dev server URL differs from `finding.page_url`, read `base_url` from `.super-design/sessions/<id>/scope.json` (written by sd-audit) and rewrite the path portion. If unreachable after 1 retry → mark `after_capture=skipped`, still record the fix in fix-results.json, log reason.
|
|
85
|
+
|
|
86
|
+
b. Drive Playwright MCP (sequential, not parallel):
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
mcp__playwright__browser_resize(width, height) # from finding.viewport
|
|
90
|
+
mcp__playwright__browser_navigate(url) # finding.page_url
|
|
91
|
+
mcp__playwright__browser_wait_for(text=<copy from before-snapshot>)
|
|
92
|
+
mcp__playwright__browser_evaluate(<disable-animations snippet>)
|
|
93
|
+
<dismiss cookie banners: snapshot → role=button accept/consent → click>
|
|
94
|
+
mcp__playwright__browser_console_messages(level="error") # record, don't abort
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
c. Take TWO screenshots per finding, saved under `.super-design/sessions/<id>/screens/`:
|
|
98
|
+
|
|
99
|
+
```
|
|
100
|
+
mcp__playwright__browser_take_screenshot({
|
|
101
|
+
fullPage: true,
|
|
102
|
+
filename: "<session_dir>/screens/F-NNNN_after_full.png"
|
|
103
|
+
})
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Then re-snapshot to get a fresh `[ref=eNN]`, find the element by accessible name matching the original finding (use `finding.snapshot_quote` text), and:
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
mcp__playwright__browser_take_screenshot({
|
|
110
|
+
element: "<accessible-name or short description>",
|
|
111
|
+
ref: "<fresh ref from new snapshot>",
|
|
112
|
+
filename: "<session_dir>/screens/F-NNNN_after_element.png"
|
|
113
|
+
})
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
If the element no longer exists (e.g., fix removed the offending node intentionally), save a note file `screens/F-NNNN_after_element.missing.txt` with the reason and skip the element screenshot.
|
|
117
|
+
|
|
118
|
+
d. Record in fix-results.json entry:
|
|
119
|
+
|
|
120
|
+
```json
|
|
121
|
+
{
|
|
122
|
+
"before_full": "<path to original sd-audit full screenshot>",
|
|
123
|
+
"before_element": "<path or null — only if sd-audit captured element-level>",
|
|
124
|
+
"after_full": "screens/F-NNNN_after_full.png",
|
|
125
|
+
"after_element": "screens/F-NNNN_after_element.png" | null,
|
|
126
|
+
"after_console_errors": [...] | [],
|
|
127
|
+
"after_capture": "ok" | "skipped" | "element-missing"
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
e. Use ONE Playwright browser session for the whole Step 5.5 batch. Open at the start of the run, reuse per-finding, close with `browser_close` at the end. Never spawn parallel tabs.
|
|
132
|
+
|
|
133
|
+
6. **Record (do NOT commit)** — append a fix-results.json entry citing the finding ID, files changed, risk, verification status, and the diff hash (`git diff --no-color | sha256sum`). NEVER run `git commit`, `git add -A`, or `git push`. Committing is owned by the commit-manager agent or the user's `/commit` flow — sd-fix only stages.
|
|
134
|
+
|
|
135
|
+
Suggested commit message that commit-manager (or the user) can copy when they decide to commit:
|
|
127
136
|
|
|
128
137
|
```
|
|
129
138
|
fix(<cat>): [F-NNNN] <short desc>
|
|
@@ -134,18 +143,18 @@ Risk: <TRIVIAL|LOW|MEDIUM|HIGH>
|
|
|
134
143
|
Verification: technical passed, semantic passed
|
|
135
144
|
|
|
136
145
|
Applied by: super-design sd-fix (<model>)
|
|
137
|
-
|
|
146
|
+
Session: <SESSION_ID>
|
|
138
147
|
```
|
|
139
148
|
|
|
140
149
|
7. **Report** — append to fix-results.json incrementally. After the full batch:
|
|
141
150
|
|
|
142
|
-
|
|
151
|
+
a. Render `docs/super-design/sessions/<session-id>/fix-report.md` using `.claude/skills/super-design/templates/fix-report.md.tpl`. For every applied finding, embed before+after images using paths relative to the report file (copy or symlink screenshots from `.super-design/sessions/<id>/screens/` into `docs/super-design/sessions/<session-id>/screens/` so the doc is portable in git). Proposed and skipped findings list their before screenshot only.
|
|
143
152
|
|
|
144
|
-
|
|
153
|
+
b. Append a row to `docs/super-design/fix-history.md` using `fix-history.md.tpl`, including a link to the per-session `fix-report.md`.
|
|
145
154
|
|
|
146
|
-
|
|
155
|
+
c. Close the Playwright browser: `mcp__playwright__browser_close`.
|
|
147
156
|
|
|
148
|
-
|
|
157
|
+
d. If `--ci`, hand off to commit-manager to commit + push, THEN create PR via `gh` with the fix-report.md path in the body. sd-fix itself never runs `git commit`/`git push`/`gh pr create` directly.
|
|
149
158
|
|
|
150
159
|
# Template library (apply inline, don't dispatch to specialists)
|
|
151
160
|
|
|
@@ -153,25 +162,26 @@ Source of truth: `references/fix-agent-playbook.md` §7.
|
|
|
153
162
|
|
|
154
163
|
## a11y templates (A1–A15)
|
|
155
164
|
|
|
156
|
-
| ID
|
|
157
|
-
|
|
158
|
-
| A1
|
|
159
|
-
| A2
|
|
160
|
-
| A3
|
|
161
|
-
| A4
|
|
162
|
-
| A5
|
|
163
|
-
| A6
|
|
164
|
-
| A7
|
|
165
|
-
| A8
|
|
166
|
-
| A9
|
|
167
|
-
| A10 | Swap to `<button type="button">`; preserve handler + classes
|
|
168
|
-
| A11 | `role="status" aria-live="polite"`; `role="alert"` for urgent
|
|
169
|
-
| A12 | Skip-link first focusable; `<main id="main-content" tabindex="-1">`
|
|
170
|
-
| A13 | `aria-current="page"` on active NavLink
|
|
171
|
-
| A14 | aria-label + aria-hidden on SVG
|
|
172
|
-
| A15 | `<caption>`, `<thead><th scope="col">`, `<th scope="row">`
|
|
165
|
+
| ID | Fix | Framework notes |
|
|
166
|
+
| --- | -------------------------------------------------------------------------- | --------------------------------------------------------------- |
|
|
167
|
+
| A1 | alt="<meaningful>" or alt="" for decorative + role="presentation" | React: `alt=""` ; Vue/Svelte/Astro/HTML: `alt=""` |
|
|
168
|
+
| A2 | `<label htmlFor/for>` wrap, or aria-label for icon-only | React: `htmlFor`, Vue/Svelte/Astro/HTML: `for` |
|
|
169
|
+
| A3 | `aria-label` OR `<span class="sr-only">` + svg aria-hidden focusable=false | Same across frameworks |
|
|
170
|
+
| A4 | Correct heading level; preserve visual via class | Same |
|
|
171
|
+
| A5 | Nearest palette token meeting 4.5:1 text / 3:1 large/UI | Read design_tokens cache |
|
|
172
|
+
| A6 | `:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px }` | CSS file or styled-components |
|
|
173
|
+
| A7 | `<html lang="en">` in layout | React: `app/layout.tsx`, Nuxt: `app.vue`, Astro: `Layout.astro` |
|
|
174
|
+
| A8 | Anchor accessible name via text, aria-label, or child alt | Same |
|
|
175
|
+
| A9 | `aria-expanded={open} aria-controls="id"` on toggle | React camelCase, others kebab |
|
|
176
|
+
| A10 | Swap to `<button type="button">`; preserve handler + classes | All frameworks |
|
|
177
|
+
| A11 | `role="status" aria-live="polite"`; `role="alert"` for urgent | Same |
|
|
178
|
+
| A12 | Skip-link first focusable; `<main id="main-content" tabindex="-1">` | Layout file |
|
|
179
|
+
| A13 | `aria-current="page"` on active NavLink | React: router hook, Vue: v-bind :aria-current |
|
|
180
|
+
| A14 | aria-label + aria-hidden on SVG | Same |
|
|
181
|
+
| A15 | `<caption>`, `<thead><th scope="col">`, `<th scope="row">` | Same |
|
|
173
182
|
|
|
174
183
|
**Never auto-apply:**
|
|
184
|
+
|
|
175
185
|
- Invent alt text for ambiguous subjects → needs_human
|
|
176
186
|
- Swap contrast token across brand-primary → needs_human
|
|
177
187
|
- Replace `<div onClick>` with `<button>` if ancestor click handlers unknown → needs_human
|
|
@@ -179,18 +189,19 @@ Source of truth: `references/fix-agent-playbook.md` §7.
|
|
|
179
189
|
|
|
180
190
|
## design templates (V1–V8)
|
|
181
191
|
|
|
182
|
-
| ID
|
|
183
|
-
|
|
184
|
-
| V1
|
|
185
|
-
| V2
|
|
186
|
-
| V3
|
|
187
|
-
| V4
|
|
188
|
-
| V5
|
|
189
|
-
| V6
|
|
190
|
-
| V7
|
|
191
|
-
| V8
|
|
192
|
+
| ID | Fix |
|
|
193
|
+
| --- | ------------------------------------------------------------ |
|
|
194
|
+
| V1 | `p-[13px]` → `p-3` (nearest 4/8 scale token) |
|
|
195
|
+
| V2 | `text-[15px]` → `text-sm` or `text-base` (type-scale) |
|
|
196
|
+
| V3 | `rounded-[5px]` → `rounded-md` (radius token) |
|
|
197
|
+
| V4 | Off-palette color → nearest token by ΔE |
|
|
198
|
+
| V5 | Competing CTA → demote to `variant="secondary"` or `"ghost"` |
|
|
199
|
+
| V6 | Arbitrary `z-[9999]` → CSS-var token scale |
|
|
200
|
+
| V7 | Arbitrary box-shadow → `shadow-md` token |
|
|
201
|
+
| V8 | Custom `@media` → framework breakpoint token |
|
|
192
202
|
|
|
193
203
|
**Never auto-apply:**
|
|
204
|
+
|
|
194
205
|
- Change brand-primary → needs_human (broader audit required)
|
|
195
206
|
- Swap color used in >5 files → needs_human (too broad for single fix)
|
|
196
207
|
- Convert design token itself → MEDIUM, escalate
|
|
@@ -208,20 +219,21 @@ hue 0-360).
|
|
|
208
219
|
|
|
209
220
|
## ux templates (U1–U10)
|
|
210
221
|
|
|
211
|
-
| ID
|
|
212
|
-
|
|
213
|
-
| U1
|
|
214
|
-
| U2
|
|
215
|
-
| U3
|
|
216
|
-
| U4
|
|
217
|
-
| U5
|
|
218
|
-
| U6
|
|
219
|
-
| U7
|
|
220
|
-
| U8
|
|
221
|
-
| U9
|
|
222
|
-
| U10 | No retry on network fail → backoff for idempotent GET; explicit retry button for POST
|
|
222
|
+
| ID | Fix |
|
|
223
|
+
| --- | ------------------------------------------------------------------------------------------------ |
|
|
224
|
+
| U1 | Placeholder-as-label → add visible `<label>`; keep placeholder as format hint |
|
|
225
|
+
| U2 | Loading state → `disabled + aria-busy + Spinner + label change + role="status"` |
|
|
226
|
+
| U3 | Empty state → ternary render `EmptyState` component |
|
|
227
|
+
| U4 | Error state → `{error && <div role="alert">...<button onClick={retry}>Try again</button></div>}` |
|
|
228
|
+
| U5 | Destructive without confirm → native `<dialog>`; typed confirm for high-risk |
|
|
229
|
+
| U6 | No undo → optimistic UI + 6s setTimeout + toast Undo action |
|
|
230
|
+
| U7 | Paste blocked on password → remove onPaste / autocomplete="off" |
|
|
231
|
+
| U8 | Missing autocomplete on login → `username`, `current-password`, `new-password`, `one-time-code` |
|
|
232
|
+
| U9 | Errors not announced → summary `role="alert"` + per-field `aria-invalid` + `aria-describedby` |
|
|
233
|
+
| U10 | No retry on network fail → backoff for idempotent GET; explicit retry button for POST |
|
|
223
234
|
|
|
224
235
|
**Never auto-apply:**
|
|
236
|
+
|
|
225
237
|
- Add `<dialog>` if >1 existing modal implementation → needs_human (inconsistency)
|
|
226
238
|
- Change form submission semantics → needs_human
|
|
227
239
|
- Introduce new dependency for Undo toast lib → needs_human
|
|
@@ -232,25 +244,26 @@ Source: `.claude/skills/mobile-app-patterns/SKILL.md` — copy snippets verbatim
|
|
|
232
244
|
Apply ONLY when `finding.viewport` is `mobile` (≤768px). Desktop/tablet
|
|
233
245
|
mobile-pattern findings → needs_human (UI architecture decision).
|
|
234
246
|
|
|
235
|
-
| ID
|
|
236
|
-
|
|
237
|
-
| M1
|
|
238
|
-
| M2
|
|
239
|
-
| M3
|
|
240
|
-
| M4
|
|
241
|
-
| M5
|
|
242
|
-
| M6
|
|
243
|
-
| M7
|
|
244
|
-
| M8
|
|
245
|
-
| M9
|
|
246
|
-
| M10 | Server failure without error state → apply U4 template; ensure retry button is 44px tall and sticky above safe-area
|
|
247
|
-
| M11 | Missing safe-area insets → `padding-top: env(safe-area-inset-top)` on header, `padding-bottom: env(safe-area-inset-bottom)` on bottom nav/CTA. `viewport-fit=cover` in meta viewport
|
|
248
|
-
| M12 | `100vh` anywhere → `100svh` primary, `100dvh` fallback, `-webkit-fill-available` legacy. Replace all occurrences in one file
|
|
249
|
-
| M13 | Inner scroll conflicting with browser pull → `overscroll-behavior: contain` on the inner scroll container
|
|
250
|
-
| M14 | Primary list without pull-to-refresh → propose integration of `react-pull-to-refresh` or Framer gesture; register refresh handler with existing query-key invalidation
|
|
251
|
-
| M15 | Swipe-action row without peek → add `transform: translateX(-8px)` reveal on first render, animate back after 600ms (framer keyframes). Ensure long-press fallback + trailing `[⋯]` menu button
|
|
247
|
+
| ID | Fix | Risk | Pattern |
|
|
248
|
+
| --- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | ------------------------------------------------ |
|
|
249
|
+
| M1 | Hamburger-only nav → `<nav class="fixed inset-x-0 bottom-0 ...">` bottom tab bar (3–5 destinations, fill-icon + label, safe-area-inset-bottom padding) | MEDIUM | needs_human for tab selection |
|
|
250
|
+
| M2 | Metric cards in `flex-col` → `<ul class="divide-y">` compact list rows (py-3 px-4, icon + label on left, tabular-nums value on right). For the hero metric extract into `<section>` with 4xl tabular-nums number + delta chip | LOW | auto when only one metric-card block |
|
|
251
|
+
| M3 | `<table>` at ≤768px → card-per-row (`<article>` with primary text + metadata chips + trailing `[⋯]` menu) OR compact list (avatar + two lines + trailing meta). Preserve sort/filter controls above | MEDIUM | needs_human if >3 columns carry semantic meaning |
|
|
252
|
+
| M4 | Input `font-size < 16px` → `font-size: max(16px, 1rem)` (Tailwind: `text-base` or `text-[max(16px,1rem)]`). Prevents iOS Safari zoom-on-focus | TRIVIAL | auto |
|
|
253
|
+
| M5 | Touch target <44×44 → wrap interactive node in `<button class="size-11 flex items-center justify-center">` keeping inner glyph. Add 8px+ gap to adjacent targets | LOW | auto for isolated buttons |
|
|
254
|
+
| M6 | Centered modal on mobile → migrate to bottom sheet via Vaul/Radix Drawer (`<Drawer.Root>` + `Drawer.Content className="fixed inset-x-0 bottom-0 rounded-t-2xl"`). Full-screen variant for flows | MEDIUM | needs_human — swap affects all call sites |
|
|
255
|
+
| M7 | Hover-only affordance → gate with `@media (hover: hover)`; add tap equivalent (visible button, long-press menu, or always-on chip) | LOW | auto for tooltip-only hovers |
|
|
256
|
+
| M8 | Async action without loading state → apply U2 template (disabled + aria-busy + Spinner + label change + role="status") | TRIVIAL | auto |
|
|
257
|
+
| M9 | Zero-data view without empty state → apply U3 template with mobile-specific illustration+CTA (full-width button) | LOW | auto |
|
|
258
|
+
| M10 | Server failure without error state → apply U4 template; ensure retry button is 44px tall and sticky above safe-area | LOW | auto |
|
|
259
|
+
| M11 | Missing safe-area insets → `padding-top: env(safe-area-inset-top)` on header, `padding-bottom: env(safe-area-inset-bottom)` on bottom nav/CTA. `viewport-fit=cover` in meta viewport | TRIVIAL | auto |
|
|
260
|
+
| M12 | `100vh` anywhere → `100svh` primary, `100dvh` fallback, `-webkit-fill-available` legacy. Replace all occurrences in one file | TRIVIAL | auto |
|
|
261
|
+
| M13 | Inner scroll conflicting with browser pull → `overscroll-behavior: contain` on the inner scroll container | TRIVIAL | auto |
|
|
262
|
+
| M14 | Primary list without pull-to-refresh → propose integration of `react-pull-to-refresh` or Framer gesture; register refresh handler with existing query-key invalidation | MEDIUM | needs_human — new dependency |
|
|
263
|
+
| M15 | Swipe-action row without peek → add `transform: translateX(-8px)` reveal on first render, animate back after 600ms (framer keyframes). Ensure long-press fallback + trailing `[⋯]` menu button | MEDIUM | needs_human if no existing swipe-action library |
|
|
252
264
|
|
|
253
265
|
**Never auto-apply:**
|
|
266
|
+
|
|
254
267
|
- Any `M*` fix when finding affects >1 layout component — UI architecture decision
|
|
255
268
|
- Adding a drawer/sheet dependency (Vaul, vaul-drawer) without user confirmation
|
|
256
269
|
- Converting a table to cards when columns drive business logic (sortable compound filters)
|
|
@@ -268,32 +281,36 @@ Source: `.claude/skills/super-design/references/design-skills-catalog.md`.
|
|
|
268
281
|
2. Write `.super-design/sessions/<id>/proposals/F-NNNN_design-skill-advisory.md`
|
|
269
282
|
using this structure:
|
|
270
283
|
|
|
271
|
-
|
|
272
|
-
|
|
284
|
+
```markdown
|
|
285
|
+
# F-NNNN — Design-skill advisory (NON-FIX)
|
|
286
|
+
|
|
287
|
+
**Rule:** design-intelligence-design-system-coherence
|
|
288
|
+
**Risk:** HIGH (aesthetic change requires human sign-off)
|
|
289
|
+
|
|
290
|
+
## Current state
|
|
273
291
|
|
|
274
|
-
|
|
275
|
-
**Risk:** HIGH (aesthetic change requires human sign-off)
|
|
292
|
+
<embedded finding.screenshot_path + finding.finding one-liner>
|
|
276
293
|
|
|
277
|
-
|
|
278
|
-
<embedded finding.screenshot_path + finding.finding one-liner>
|
|
294
|
+
## Recommended skills
|
|
279
295
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
- When to recommend: <catalog "When to recommend" column>
|
|
296
|
+
<for each id in finding.recommended_skills:>
|
|
297
|
+
- **<id>** — <description from design-skills-catalog selection matrix>
|
|
298
|
+
- Visual signature: <catalog signature column>
|
|
299
|
+
- When to recommend: <catalog "When to recommend" column>
|
|
285
300
|
|
|
286
|
-
|
|
287
|
-
<best-matching competitor screenshots from
|
|
288
|
-
.cache/evidence/<slug>/<viewport>/components/ cited as reference — pick
|
|
289
|
-
the 2 closest to the recommended aesthetic>
|
|
301
|
+
## Competitor evidence
|
|
290
302
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
303
|
+
<best-matching competitor screenshots from
|
|
304
|
+
.cache/evidence/<slug>/<viewport>/components/ cited as reference — pick
|
|
305
|
+
the 2 closest to the recommended aesthetic>
|
|
306
|
+
|
|
307
|
+
## Next step for the user
|
|
308
|
+
|
|
309
|
+
Run `/frontend-design` (or re-run super-design with the chosen skill
|
|
310
|
+
active) to apply this direction. sd-fix cannot auto-apply aesthetic
|
|
311
|
+
realignment because every subsequent fix depends on the chosen
|
|
312
|
+
tokens.
|
|
313
|
+
```
|
|
297
314
|
|
|
298
315
|
3. Append to fix-report.md under a "Proposed aesthetic direction" section,
|
|
299
316
|
NOT under "Applied fixes" — the image diff format is
|
|
@@ -307,20 +324,21 @@ without writing code.**
|
|
|
307
324
|
|
|
308
325
|
## perf templates (P1–P10)
|
|
309
326
|
|
|
310
|
-
| ID
|
|
311
|
-
|
|
312
|
-
| P1
|
|
313
|
-
| P2
|
|
314
|
-
| P3
|
|
315
|
-
| P4
|
|
316
|
-
| P5
|
|
317
|
-
| P6
|
|
318
|
-
| P7
|
|
319
|
-
| P8
|
|
320
|
-
| P9
|
|
321
|
-
| P10 | No Cache-Control on static → `public, max-age=31536000, immutable` (hashed only)
|
|
327
|
+
| ID | Fix |
|
|
328
|
+
| --- | ---------------------------------------------------------------------------------------- |
|
|
329
|
+
| P1 | `<img>` without w/h → add width + height; CSS `max-width:100%; height:auto` |
|
|
330
|
+
| P2 | Missing `loading="lazy"` → add to below-fold ONLY (NEVER LCP) |
|
|
331
|
+
| P3 | Missing `fetchpriority="high"` on LCP → add (ONE per route, confirm LCP first) |
|
|
332
|
+
| P4 | Embed CLS → wrap in aspect-ratio div or `aspect-video` |
|
|
333
|
+
| P5 | Render-blocking CSS → inline critical; `rel="preload" as="style" onload="..."` (MEDIUM) |
|
|
334
|
+
| P6 | Font FOIT → `font-display: swap`; preload critical weight `crossorigin` |
|
|
335
|
+
| P7 | Large JS bundle → `dynamic(() => import, {ssr:false})` / `React.lazy` (MEDIUM — propose) |
|
|
336
|
+
| P8 | No preconnect 3P → `<link rel="preconnect" crossorigin>` (≤4 origins) |
|
|
337
|
+
| P9 | `<img>` not `next/image` → swap; whitelist hostname in `remotePatterns` |
|
|
338
|
+
| P10 | No Cache-Control on static → `public, max-age=31536000, immutable` (hashed only) |
|
|
322
339
|
|
|
323
340
|
**Hard blockers (stop and ask):**
|
|
341
|
+
|
|
324
342
|
- `loading="lazy"` on image that might be LCP → verify via Playwright first
|
|
325
343
|
- `fetchpriority="high"` on >1 image per route → only one allowed
|
|
326
344
|
- Code-splitting boundary → MEDIUM propose, never auto
|
|
@@ -332,6 +350,7 @@ without writing code.**
|
|
|
332
350
|
- Never `Write` existing file unless fully replacing.
|
|
333
351
|
- Never auto-apply risk ≥ MEDIUM.
|
|
334
352
|
- Never touch `.git`, `node_modules`, `dist`, `build`, `.next`, lockfiles.
|
|
353
|
+
- **Never run `git commit`, `git add -A`, `git push`, `git stash`, `git reset --hard`, `git rebase`, `git merge`, or `gh pr create`.** Stage edits surgically (`git add -- <file>` for the specific files in `finding.files_affected` is OK). All commit/push/PR work is delegated to commit-manager or the user's `/commit` flow.
|
|
335
354
|
- Never invent alt text for ambiguous subjects → needs_human.
|
|
336
355
|
- Never add `loading="lazy"` to potential LCP image.
|
|
337
356
|
- Never set `fetchpriority="high"` on >1 image per route.
|
|
@@ -342,12 +361,12 @@ without writing code.**
|
|
|
342
361
|
- Never fabricate after-screenshots. No real browser call → no after image.
|
|
343
362
|
- Never run Step 5.5 in parallel against the same browser tab.
|
|
344
363
|
- Never auto-apply DSC-1 (design-skill advisory) — write the proposal, then stop.
|
|
345
|
-
- Never auto-apply any M
|
|
364
|
+
- Never auto-apply any M\* fix for desktop/tablet viewports — mobile patterns do not generalize upward.
|
|
346
365
|
- Never introduce a mobile-pattern dependency (Vaul, vaul-drawer, react-pull-to-refresh, react-swipeable-list) without user confirmation.
|
|
347
366
|
|
|
348
367
|
# Evidence rule
|
|
349
368
|
|
|
350
|
-
Every applied fix MUST cite finding ID in commit message
|
|
369
|
+
Every applied fix MUST cite finding ID in fix-results.json AND in the suggested commit message stored alongside (for commit-manager to pick up). No finding ID → no fix is recorded as applied.
|
|
351
370
|
|
|
352
371
|
# Preserve these when editing
|
|
353
372
|
|
|
@@ -362,7 +381,7 @@ Every applied fix MUST cite finding ID in commit message AND fix-results.json. N
|
|
|
362
381
|
# Self-check before completing
|
|
363
382
|
|
|
364
383
|
- [ ] fix-results.json has entry for every finding in findings.json
|
|
365
|
-
- [ ] Applied count matches commit
|
|
384
|
+
- [ ] Applied count matches the number of fix-results entries with `applied=true` (commits are NOT created by sd-fix — handing off to commit-manager is the user's call)
|
|
366
385
|
- [ ] Tests and types passing on tip
|
|
367
386
|
- [ ] Every applied finding has `after_full` screenshot on disk (or `after_capture=skipped` with reason)
|
|
368
387
|
- [ ] Every applied finding has `after_element` screenshot on disk OR a `.missing.txt` note (or `after_capture=skipped`)
|