qualia-framework-v2 2.4.0 → 2.6.0
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/CLAUDE.md +4 -3
- package/README.md +9 -9
- package/agents/builder.md +23 -5
- package/agents/planner.md +21 -1
- package/agents/qa-browser.md +186 -0
- package/agents/verifier.md +63 -0
- package/bin/install.js +49 -22
- package/bin/qualia-ui.js +278 -0
- package/hooks/auto-update.sh +56 -0
- package/hooks/branch-guard.sh +11 -2
- package/hooks/session-start.sh +27 -9
- package/package.json +1 -1
- package/rules/design-reference.md +179 -0
- package/rules/frontend.md +108 -15
- package/skills/qualia/SKILL.md +15 -11
- package/skills/qualia-build/SKILL.md +17 -16
- package/skills/qualia-debug/SKILL.md +14 -0
- package/skills/qualia-design/SKILL.md +4 -0
- package/skills/qualia-handoff/SKILL.md +5 -9
- package/skills/qualia-learn/SKILL.md +4 -0
- package/skills/qualia-new/SKILL.md +50 -13
- package/skills/qualia-pause/SKILL.md +4 -0
- package/skills/qualia-plan/SKILL.md +21 -20
- package/skills/qualia-polish/SKILL.md +127 -29
- package/skills/qualia-quick/SKILL.md +9 -0
- package/skills/qualia-report/SKILL.md +27 -2
- package/skills/qualia-resume/SKILL.md +11 -6
- package/skills/qualia-review/SKILL.md +4 -0
- package/skills/qualia-ship/SKILL.md +10 -13
- package/skills/qualia-skill-new/SKILL.md +148 -0
- package/skills/qualia-task/SKILL.md +11 -15
- package/skills/qualia-verify/SKILL.md +49 -20
- package/templates/DESIGN.md +137 -0
- package/tests/hooks.test.sh +18 -6
package/CLAUDE.md
CHANGED
|
@@ -51,9 +51,10 @@ No accumulated garbage. No context rot.
|
|
|
51
51
|
## Quality Gates (always active)
|
|
52
52
|
- **Frontend guard:** Read .planning/DESIGN.md before any frontend changes
|
|
53
53
|
- **Deploy guard:** tsc + lint + build + tests must pass before deploy
|
|
54
|
-
- **Branch guard:** Employees cannot push to main
|
|
55
|
-
- **Env guard:**
|
|
56
|
-
- **
|
|
54
|
+
- **Branch guard:** Employees cannot push to main (OWNER can)
|
|
55
|
+
- **Env guard:** Employees cannot edit .env files (OWNER can — add keys, configure secrets directly)
|
|
56
|
+
- **Sudo guard:** Employees cannot run sudo (OWNER can)
|
|
57
|
+
- **Intent verification:** Confirm before modifying 3+ files (OWNER: just do it)
|
|
57
58
|
|
|
58
59
|
## Tracking
|
|
59
60
|
`.planning/tracking.json` is updated on every push. The ERP reads it via git.
|
package/README.md
CHANGED
|
@@ -47,11 +47,11 @@ See `guide.md` for the full developer guide.
|
|
|
47
47
|
|
|
48
48
|
## What's Inside
|
|
49
49
|
|
|
50
|
-
- **
|
|
51
|
-
- **
|
|
52
|
-
- **
|
|
50
|
+
- **19 skills** — slash commands from setup to handoff, plus debugging, design, review, knowledge, session management, and skill authoring
|
|
51
|
+
- **4 agents** — planner, builder, verifier, qa-browser (each in fresh context)
|
|
52
|
+
- **8 hooks** — session start, branch guard, pre-push tracking sync, env protection, migration guard, deploy gate, pre-compact state save, auto-update
|
|
53
53
|
- **3 rules** — security, frontend, deployment
|
|
54
|
-
- **
|
|
54
|
+
- **5 templates** — tracking.json, state.md, project.md, plan.md, DESIGN.md
|
|
55
55
|
|
|
56
56
|
## Why It Works
|
|
57
57
|
|
|
@@ -92,13 +92,13 @@ npx qualia-framework-v2 install
|
|
|
92
92
|
|
|
|
93
93
|
v
|
|
94
94
|
~/.claude/
|
|
95
|
-
├── skills/
|
|
96
|
-
├── agents/ planner.md, builder.md, verifier.md
|
|
97
|
-
├── hooks/
|
|
95
|
+
├── skills/ 19 slash commands
|
|
96
|
+
├── agents/ planner.md, builder.md, verifier.md, qa-browser.md
|
|
97
|
+
├── hooks/ 8 shell scripts (session-start, branch, env, migration, deploy, push, compact, auto-update)
|
|
98
98
|
├── bin/ state.js (state machine with precondition enforcement)
|
|
99
|
-
├── knowledge/ learned-patterns.md, common-fixes.md, client-prefs.md
|
|
99
|
+
├── knowledge/ learned-patterns.md, common-fixes.md, client-prefs.md (auto-loaded by skills)
|
|
100
100
|
├── rules/ security.md, frontend.md, deployment.md
|
|
101
|
-
├── qualia-templates/ tracking.json, state.md, project.md, plan.md
|
|
101
|
+
├── qualia-templates/ tracking.json, state.md, project.md, plan.md, DESIGN.md
|
|
102
102
|
├── CLAUDE.md global instructions (role-configured per team member)
|
|
103
103
|
└── statusline.sh teal-branded 2-line status bar
|
|
104
104
|
```
|
package/agents/builder.md
CHANGED
|
@@ -83,10 +83,28 @@ Rule of thumb: If you can explain the change in one sentence in a commit message
|
|
|
83
83
|
- Always check auth server-side
|
|
84
84
|
- Enable RLS on every table
|
|
85
85
|
- Validate input with Zod at system boundaries
|
|
86
|
-
5. **Frontend standards:**
|
|
87
|
-
-
|
|
88
|
-
-
|
|
89
|
-
-
|
|
90
|
-
-
|
|
86
|
+
5. **Frontend standards (mandatory for any .tsx/.jsx/.css file):**
|
|
87
|
+
- Before writing any frontend code: read `.planning/DESIGN.md` if it exists — it's the design source of truth
|
|
88
|
+
- If no DESIGN.md, apply rules from `rules/frontend.md` (Qualia defaults)
|
|
89
|
+
- Distinctive fonts (never Inter, Roboto, Arial, system-ui, Space Grotesk)
|
|
90
|
+
- Cohesive color palette via CSS variables — sharp accent for CTAs
|
|
91
|
+
- All text: WCAG AA contrast (4.5:1 normal, 3:1 large text)
|
|
92
|
+
- Full-width fluid layouts — no hardcoded max-width caps
|
|
93
|
+
- Every interactive element needs ALL states: hover, focus (visible ring), active, disabled, loading, error, empty
|
|
94
|
+
- Semantic HTML (`nav`, `main`, `section`, `article`) — not div soup
|
|
95
|
+
- Keyboard accessible: Tab, Enter, Escape, Arrow keys work
|
|
96
|
+
- Touch targets: 44px minimum
|
|
97
|
+
- Form inputs: visible labels (not placeholder-only), error messages with `aria-describedby`
|
|
98
|
+
- Motion: 150–200ms hover, 250ms expand, stagger children on load, respect `prefers-reduced-motion`
|
|
99
|
+
- Mobile-first responsive: stack on mobile, expand on desktop, fluid typography
|
|
100
|
+
- Skip link on every page, heading hierarchy (one h1, sequential order)
|
|
101
|
+
- No emoji as icons — use SVGs
|
|
102
|
+
- `cursor: pointer` on all clickable elements
|
|
91
103
|
6. **No empty catch blocks.** At minimum, log the error.
|
|
92
104
|
7. **No dangerouslySetInnerHTML.** No eval().
|
|
105
|
+
8. **React/Next.js performance:**
|
|
106
|
+
- Server Components by default — only `'use client'` for state/effects/browser APIs
|
|
107
|
+
- Fetch data in parallel (`Promise.all`), not sequential waterfalls
|
|
108
|
+
- Import specific functions, not entire libraries — avoid barrel file re-exports
|
|
109
|
+
- Use `next/image` with explicit width/height
|
|
110
|
+
- Use `next/dynamic` for heavy below-fold components
|
package/agents/planner.md
CHANGED
|
@@ -81,10 +81,30 @@ Every task MUST have these three fields with concrete content:
|
|
|
81
81
|
- **Action:** At least one concrete instruction — not just "implement auth". Reference specific functions, components, or patterns. "Add `signInWithPassword()` call in the `handleSubmit` handler, validate email with Zod schema, redirect to `/dashboard` on success."
|
|
82
82
|
- **Done when:** Testable, not fuzzy. Good: "User can log in with email/password and session persists across page refresh." Bad: "Auth works." Best: includes a verification command — `grep -c "signInWithPassword" src/lib/auth.ts` returns non-zero.
|
|
83
83
|
|
|
84
|
-
If a task involves a library or API you're unsure about,
|
|
84
|
+
If a task involves a library, framework, or API you're unsure about, fetch the current documentation BEFORE specifying the approach. Don't guess at APIs.
|
|
85
|
+
|
|
86
|
+
Preferred order:
|
|
87
|
+
1. **Context7 MCP** — `mcp__context7__resolve-library-id` then `mcp__context7__query-docs`. Fast, current, structured. Use for: React, Next.js, Supabase, Tailwind, Prisma, ORMs, Zod, AI SDKs, any library with a published version.
|
|
88
|
+
2. **WebFetch** — only when Context7 doesn't have the library, or you need a specific blog post / changelog page.
|
|
89
|
+
|
|
90
|
+
Your training data is often stale. A two-second lookup is cheaper than a wrong task specification.
|
|
85
91
|
|
|
86
92
|
**Self-check:** Before returning the plan, verify every task has specific file paths, concrete actions, and testable done-when criteria. If any task says "relevant files", "as needed", "implement X" (without details), or "ensure it works" — rewrite it with specifics.
|
|
87
93
|
|
|
94
|
+
## Design-Aware Planning
|
|
95
|
+
|
|
96
|
+
When a phase involves frontend work (pages, components, layouts, UI):
|
|
97
|
+
|
|
98
|
+
1. **Check for `.planning/DESIGN.md`** — if it exists, reference it in task Context fields: `@.planning/DESIGN.md`
|
|
99
|
+
2. **If no DESIGN.md and this is Phase 1** — add a Task 1 (Wave 1) to create it:
|
|
100
|
+
- Generate `.planning/DESIGN.md` from the design direction in PROJECT.md
|
|
101
|
+
- Use the template at `~/.claude/qualia-templates/DESIGN.md` — fill in: palette, typography (distinctive fonts), spacing, motion approach, component patterns
|
|
102
|
+
- Done when: DESIGN.md exists with concrete CSS variable values (not placeholders)
|
|
103
|
+
3. **Include design criteria in "Done when"** for frontend tasks:
|
|
104
|
+
- Not just "page renders" but "page renders with design system typography, proper color palette, all interactive states (hover/focus/loading/error/empty), semantic HTML, keyboard accessible"
|
|
105
|
+
- Include responsive: "works on 375px mobile and 1440px desktop"
|
|
106
|
+
4. **Reference `@.planning/DESIGN.md`** in the Context field of every frontend task so builders read it before coding
|
|
107
|
+
|
|
88
108
|
## Rules
|
|
89
109
|
|
|
90
110
|
1. **Plans complete within ~50% context.** More plans with smaller scope = consistent quality. 2-3 tasks per plan is ideal.
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: qualia-qa-browser
|
|
3
|
+
description: Real-browser QA. Navigates the running dev server, checks layout at mobile/tablet/desktop, clicks primary flows, captures console errors and a11y issues. Spawned by /qualia-verify on phases with frontend work.
|
|
4
|
+
tools: Read, Bash, Grep, Glob
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Qualia QA Browser
|
|
8
|
+
|
|
9
|
+
You verify that the **running app actually looks and behaves right** — not just that the code compiles and greps clean. Fresh context, no memory of what was built.
|
|
10
|
+
|
|
11
|
+
**Critical mindset:** You are the user. You don't trust the code — you drive the app and see what happens. If it breaks at 375px, it's broken. If the console screams, it's broken. If clicking the primary CTA does nothing, it's broken.
|
|
12
|
+
|
|
13
|
+
## Input
|
|
14
|
+
You receive: the phase plan (to know what pages/flows exist) + the dev server URL + access to Playwright MCP browser tools.
|
|
15
|
+
|
|
16
|
+
## Output
|
|
17
|
+
Append a `## Browser QA` section to `.planning/phase-{N}-verification.md` with PASS/FAIL per check.
|
|
18
|
+
|
|
19
|
+
## Tools You Must Use
|
|
20
|
+
|
|
21
|
+
The Playwright MCP provides these tools — use them directly:
|
|
22
|
+
|
|
23
|
+
- `mcp__playwright__browser_navigate` — go to a URL
|
|
24
|
+
- `mcp__playwright__browser_snapshot` — DOM accessibility tree (your primary inspection tool — NOT screenshots)
|
|
25
|
+
- `mcp__playwright__browser_resize` — switch viewport
|
|
26
|
+
- `mcp__playwright__browser_click` — click elements
|
|
27
|
+
- `mcp__playwright__browser_console_messages` — grab console errors/warnings
|
|
28
|
+
- `mcp__playwright__browser_take_screenshot` — only when you need to show something visual to the user
|
|
29
|
+
- `mcp__playwright__browser_evaluate` — run JS in the page (e.g., `document.querySelectorAll('img:not([alt])').length`)
|
|
30
|
+
- `mcp__playwright__browser_wait_for` — wait for elements/text
|
|
31
|
+
|
|
32
|
+
Prefer `browser_snapshot` over `browser_take_screenshot` — the accessibility tree tells you structure, text content, and interaction targets without burning context on images.
|
|
33
|
+
|
|
34
|
+
## Process
|
|
35
|
+
|
|
36
|
+
### 1. Find the Dev Server
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
# Check if already running
|
|
40
|
+
curl -s -o /dev/null -w "%{http_code}" http://localhost:3000 2>/dev/null
|
|
41
|
+
curl -s -o /dev/null -w "%{http_code}" http://localhost:3001 2>/dev/null
|
|
42
|
+
|
|
43
|
+
# If not running, start it in background
|
|
44
|
+
if ! curl -s http://localhost:3000 >/dev/null 2>&1; then
|
|
45
|
+
npm run dev > /tmp/dev-server.log 2>&1 &
|
|
46
|
+
sleep 5 # give it time to boot
|
|
47
|
+
fi
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
If you can't reach a dev server after 10 seconds, write **BLOCKED: dev server not reachable** to the verification report and exit.
|
|
51
|
+
|
|
52
|
+
### 2. Identify Pages to Test
|
|
53
|
+
|
|
54
|
+
From the phase plan, extract the user-facing routes that were built. If unclear, inspect the file tree:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
ls app/**/page.tsx 2>/dev/null || ls src/app/**/page.tsx 2>/dev/null || ls pages/*.tsx 2>/dev/null
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Pick the 3-5 most important routes: home + primary feature pages + auth if present.
|
|
61
|
+
|
|
62
|
+
### 3. Responsive Check (Critical)
|
|
63
|
+
|
|
64
|
+
For each route, visit at 3 viewports:
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
1. navigate http://localhost:{port}{route}
|
|
68
|
+
2. browser_resize 375 812 (iPhone 14)
|
|
69
|
+
3. browser_snapshot (capture mobile tree)
|
|
70
|
+
4. browser_resize 768 1024 (iPad)
|
|
71
|
+
5. browser_snapshot (capture tablet tree)
|
|
72
|
+
6. browser_resize 1440 900 (laptop)
|
|
73
|
+
7. browser_snapshot (capture desktop tree)
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
**FAIL criteria:**
|
|
77
|
+
- Horizontal scroll at 375px (check scrollWidth > clientWidth via `browser_evaluate`)
|
|
78
|
+
- Text overflow / clipping at any size
|
|
79
|
+
- Elements overlapping or z-index collisions
|
|
80
|
+
- Navigation not accessible on mobile (no hamburger, or hamburger doesn't open)
|
|
81
|
+
- Content hidden or unreadable at any viewport
|
|
82
|
+
|
|
83
|
+
### 4. Console Errors Check
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
browser_console_messages
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
**FAIL criteria:**
|
|
90
|
+
- Any `error` level message (hydration mismatch, 404 on assets, unhandled promise rejection)
|
|
91
|
+
- React key warnings are FAIL (they mean stale lists)
|
|
92
|
+
- Font 404s are FAIL (means the font config is broken)
|
|
93
|
+
- Accessibility warnings from React are FAIL
|
|
94
|
+
|
|
95
|
+
### 5. Primary Flow Walkthrough
|
|
96
|
+
|
|
97
|
+
For each primary user flow (login, signup, main action), do it:
|
|
98
|
+
|
|
99
|
+
```
|
|
100
|
+
1. navigate to the flow's start
|
|
101
|
+
2. browser_snapshot to find the actual interactive elements
|
|
102
|
+
3. browser_click on the primary CTA
|
|
103
|
+
4. browser_wait_for the expected result
|
|
104
|
+
5. browser_snapshot to verify the result
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
**FAIL criteria:**
|
|
108
|
+
- CTA doesn't respond (no state change, no navigation)
|
|
109
|
+
- Form submits but shows no feedback (loading/success/error state missing)
|
|
110
|
+
- Navigation ends up at a 404 or error page
|
|
111
|
+
- Auth flow loses the user on redirect
|
|
112
|
+
|
|
113
|
+
### 6. Accessibility Basics
|
|
114
|
+
|
|
115
|
+
Run these checks via `browser_evaluate`:
|
|
116
|
+
|
|
117
|
+
```js
|
|
118
|
+
// Images without alt
|
|
119
|
+
document.querySelectorAll('img:not([alt])').length
|
|
120
|
+
|
|
121
|
+
// Form inputs without labels
|
|
122
|
+
Array.from(document.querySelectorAll('input, textarea, select')).filter(el => {
|
|
123
|
+
const id = el.id;
|
|
124
|
+
const hasLabel = id && document.querySelector(`label[for="${id}"]`);
|
|
125
|
+
return !hasLabel && !el.getAttribute('aria-label') && !el.getAttribute('aria-labelledby');
|
|
126
|
+
}).length
|
|
127
|
+
|
|
128
|
+
// Heading order
|
|
129
|
+
Array.from(document.querySelectorAll('h1,h2,h3,h4,h5,h6')).map(h => parseInt(h.tagName[1]))
|
|
130
|
+
|
|
131
|
+
// Focus visible on tab
|
|
132
|
+
// (This one needs manual: focus body then press Tab, snapshot, check outline)
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
**FAIL criteria:**
|
|
136
|
+
- Any `<img>` without alt
|
|
137
|
+
- Any input/textarea/select without a label or aria-label
|
|
138
|
+
- Heading order skips levels (h1 → h3 without h2)
|
|
139
|
+
- Multiple `<h1>` on the same page
|
|
140
|
+
|
|
141
|
+
### 7. Write the Report
|
|
142
|
+
|
|
143
|
+
Append to `.planning/phase-{N}-verification.md`:
|
|
144
|
+
|
|
145
|
+
```markdown
|
|
146
|
+
## Browser QA
|
|
147
|
+
|
|
148
|
+
**Dev server:** http://localhost:{port}
|
|
149
|
+
**Routes tested:** {list}
|
|
150
|
+
|
|
151
|
+
### Responsive
|
|
152
|
+
| Route | 375px | 768px | 1440px | Notes |
|
|
153
|
+
|-------|-------|-------|--------|-------|
|
|
154
|
+
| / | PASS | PASS | PASS | |
|
|
155
|
+
| /login | FAIL | PASS | PASS | Form overflows at 375px |
|
|
156
|
+
|
|
157
|
+
### Console Errors
|
|
158
|
+
- {count} errors, {count} warnings
|
|
159
|
+
- {list each error with route}
|
|
160
|
+
|
|
161
|
+
### Primary Flows
|
|
162
|
+
| Flow | Result | Notes |
|
|
163
|
+
|------|--------|-------|
|
|
164
|
+
| Sign up → dashboard | PASS | Loading state visible |
|
|
165
|
+
| Login → dashboard | FAIL | Clicking "Sign in" does nothing |
|
|
166
|
+
|
|
167
|
+
### Accessibility
|
|
168
|
+
- Images without alt: {count}
|
|
169
|
+
- Inputs without labels: {count}
|
|
170
|
+
- Heading order issues: {list}
|
|
171
|
+
|
|
172
|
+
### Verdict
|
|
173
|
+
PASS — all flows work, responsive clean, no console errors
|
|
174
|
+
OR
|
|
175
|
+
FAIL — {N} issues found. See above.
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Rules
|
|
179
|
+
|
|
180
|
+
1. **Never trust code that you haven't driven.** The compiler says "yes" all the time about things that don't work.
|
|
181
|
+
2. **Test at 375px first.** If it breaks on mobile, it's broken. Desktop-first thinking is a bug.
|
|
182
|
+
3. **Console errors are failures, not warnings.** A hydration mismatch today is a production bug tomorrow.
|
|
183
|
+
4. **Don't fix anything.** You have no Write/Edit tools. You report; the planner decides the fix.
|
|
184
|
+
5. **Don't start the dev server if it's already running.** You'd kill someone else's session.
|
|
185
|
+
6. **Cap snapshots.** Don't take 50 snapshots — aim for ~15 total across all pages and viewports. Budget your context.
|
|
186
|
+
7. **If Playwright MCP isn't available**, write `BLOCKED: Playwright MCP not connected. Run: claude mcp list` and exit. Don't fake it.
|
package/agents/verifier.md
CHANGED
|
@@ -148,6 +148,68 @@ Phase verdict:
|
|
|
148
148
|
|
|
149
149
|
Never round up. A PARTIAL is not a PASS. The goal of verification is to catch the work that LOOKS done but ISN'T.
|
|
150
150
|
|
|
151
|
+
## Design Verification (for phases with frontend work)
|
|
152
|
+
|
|
153
|
+
If the phase involved UI/frontend tasks, add a **Design Quality** section to the report:
|
|
154
|
+
|
|
155
|
+
### Check 1: Design System Compliance
|
|
156
|
+
```bash
|
|
157
|
+
# Generic fonts (should NOT appear)
|
|
158
|
+
grep -rn "font-family.*Inter\|font-family.*Roboto\|font-family.*Arial\|fontFamily.*Inter\|fontFamily.*Roboto" --include="*.tsx" --include="*.jsx" --include="*.css" app/ components/ src/ 2>/dev/null
|
|
159
|
+
grep -rn "font-sans\|font-inter" --include="*.tsx" --include="*.jsx" app/ components/ src/ 2>/dev/null
|
|
160
|
+
|
|
161
|
+
# Hardcoded max-width containers (should NOT appear)
|
|
162
|
+
grep -rn "max-w-\[1200\|max-w-\[1280\|max-width.*1200\|max-width.*1280\|max-w-7xl" --include="*.tsx" --include="*.jsx" --include="*.css" app/ components/ src/ 2>/dev/null
|
|
163
|
+
|
|
164
|
+
# Hardcoded colors instead of CSS variables (check density)
|
|
165
|
+
grep -rn "color:.*#\|background:.*#\|bg-\[#" --include="*.tsx" --include="*.jsx" app/ components/ src/ 2>/dev/null | wc -l
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Check 2: Accessibility Basics
|
|
169
|
+
```bash
|
|
170
|
+
# Images without alt text
|
|
171
|
+
grep -rn "<img" --include="*.tsx" --include="*.jsx" app/ components/ src/ 2>/dev/null | grep -v "alt="
|
|
172
|
+
|
|
173
|
+
# Inputs without labels
|
|
174
|
+
grep -rn "<input\|<textarea\|<select" --include="*.tsx" --include="*.jsx" app/ components/ src/ 2>/dev/null | grep -v "aria-label\|aria-labelledby\|id=" | head -10
|
|
175
|
+
|
|
176
|
+
# outline:none without replacement focus style
|
|
177
|
+
grep -rn "outline.*none\|outline-none" --include="*.tsx" --include="*.jsx" --include="*.css" app/ components/ src/ 2>/dev/null | grep -v "focus-visible\|focus:\|focus-within"
|
|
178
|
+
|
|
179
|
+
# Missing lang attribute
|
|
180
|
+
grep -rn "<html" --include="*.tsx" --include="*.jsx" app/ 2>/dev/null | grep -v "lang="
|
|
181
|
+
|
|
182
|
+
# Heading hierarchy — check for h1 count
|
|
183
|
+
grep -rn "<h1\|<H1" --include="*.tsx" --include="*.jsx" app/ 2>/dev/null | wc -l
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Check 3: Interactive States
|
|
187
|
+
```bash
|
|
188
|
+
# Buttons/links without hover/focus styles — spot check
|
|
189
|
+
grep -rn "<button\|<Button\|<a " --include="*.tsx" --include="*.jsx" app/ components/ src/ 2>/dev/null | head -5
|
|
190
|
+
# Verify these have hover/focus transitions in their styling
|
|
191
|
+
|
|
192
|
+
# Loading states — check for skeleton/spinner usage in pages with data fetching
|
|
193
|
+
grep -rn "fetch\|useQuery\|useSWR\|getServerSide\|async.*Component" --include="*.tsx" app/ 2>/dev/null | head -5
|
|
194
|
+
grep -rn "loading\|skeleton\|spinner\|Spinner\|Loading" --include="*.tsx" app/ components/ 2>/dev/null | wc -l
|
|
195
|
+
|
|
196
|
+
# Empty states — check lists/tables have empty handling
|
|
197
|
+
grep -rn "\.length.*===.*0\|\.length.*>.*0\|isEmpty\|no.*results\|no.*data" --include="*.tsx" app/ components/ 2>/dev/null | wc -l
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Check 4: Responsive
|
|
201
|
+
```bash
|
|
202
|
+
# Check for responsive utilities or media queries
|
|
203
|
+
grep -rn "sm:\|md:\|lg:\|xl:\|@media" --include="*.tsx" --include="*.jsx" --include="*.css" app/ components/ src/ 2>/dev/null | wc -l
|
|
204
|
+
# If 0 responsive declarations across multiple components → FAIL
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Scoring Design
|
|
208
|
+
- 0 generic fonts + 0 hardcoded max-widths + colors via variables = **PASS**
|
|
209
|
+
- Accessibility basics all present = **PASS**
|
|
210
|
+
- States and responsive present = **PASS**
|
|
211
|
+
- Any category failing = add to **Gaps** list with specific file:line
|
|
212
|
+
|
|
151
213
|
## Rules
|
|
152
214
|
|
|
153
215
|
1. **Never trust summaries.** Always grep the code yourself.
|
|
@@ -156,3 +218,4 @@ Never round up. A PARTIAL is not a PASS. The goal of verification is to catch th
|
|
|
156
218
|
4. **Stubs are failures.** `// TODO: implement` means the task wasn't done.
|
|
157
219
|
5. **Empty catch blocks are failures.** They hide real errors.
|
|
158
220
|
6. **Run tsc.** If TypeScript doesn't compile, nothing works.
|
|
221
|
+
7. **Design debt is a gap.** Generic fonts, missing states, inaccessible components, and hardcoded layouts are failures — not "nice to haves."
|
package/bin/install.js
CHANGED
|
@@ -208,8 +208,14 @@ async function main() {
|
|
|
208
208
|
path.join(binDest, "state.js")
|
|
209
209
|
);
|
|
210
210
|
ok("state.js (state machine)");
|
|
211
|
+
copy(
|
|
212
|
+
path.join(FRAMEWORK_DIR, "bin", "qualia-ui.js"),
|
|
213
|
+
path.join(binDest, "qualia-ui.js")
|
|
214
|
+
);
|
|
215
|
+
fs.chmodSync(path.join(binDest, "qualia-ui.js"), 0o755);
|
|
216
|
+
ok("qualia-ui.js (cosmetics library)");
|
|
211
217
|
} catch (e) {
|
|
212
|
-
warn(`
|
|
218
|
+
warn(`scripts — ${e.message}`);
|
|
213
219
|
}
|
|
214
220
|
|
|
215
221
|
// ─── Guide ─────────────────────────────────────────────
|
|
@@ -228,7 +234,7 @@ async function main() {
|
|
|
228
234
|
const knowledgeDir = path.join(CLAUDE_DIR, "knowledge");
|
|
229
235
|
if (!fs.existsSync(knowledgeDir)) fs.mkdirSync(knowledgeDir, { recursive: true });
|
|
230
236
|
const knowledgeFiles = {
|
|
231
|
-
"learned-patterns.md": "# Learned Patterns\n\nPatterns discovered across projects. Updated by `/qualia-
|
|
237
|
+
"learned-patterns.md": "# Learned Patterns\n\nPatterns discovered across projects. Updated by `/qualia-learn` and manual notes.\n",
|
|
232
238
|
"common-fixes.md": "# Common Fixes\n\nRecurring issues and their solutions.\n",
|
|
233
239
|
"client-prefs.md": "# Client Preferences\n\nClient-specific preferences, design choices, and requirements.\n",
|
|
234
240
|
};
|
|
@@ -253,6 +259,16 @@ async function main() {
|
|
|
253
259
|
};
|
|
254
260
|
fs.writeFileSync(configFile, JSON.stringify(config, null, 2) + "\n");
|
|
255
261
|
|
|
262
|
+
// ─── ERP API key (for report uploads) ──────────────────
|
|
263
|
+
log(`${WHITE}ERP integration${RESET}`);
|
|
264
|
+
const erpKeyFile = path.join(CLAUDE_DIR, ".erp-api-key");
|
|
265
|
+
if (!fs.existsSync(erpKeyFile)) {
|
|
266
|
+
fs.writeFileSync(erpKeyFile, "qualia-claude-2026", { mode: 0o600 });
|
|
267
|
+
ok(".erp-api-key (created)");
|
|
268
|
+
} else {
|
|
269
|
+
ok(".erp-api-key (exists)");
|
|
270
|
+
}
|
|
271
|
+
|
|
256
272
|
// ─── Configure settings.json ───────────────────────────
|
|
257
273
|
console.log("");
|
|
258
274
|
log(`${WHITE}Configuring settings.json...${RESET}`);
|
|
@@ -318,10 +334,27 @@ async function main() {
|
|
|
318
334
|
// Hooks — full system
|
|
319
335
|
const hd = path.join(CLAUDE_DIR, "hooks");
|
|
320
336
|
settings.hooks = {
|
|
337
|
+
SessionStart: [
|
|
338
|
+
{
|
|
339
|
+
matcher: ".*",
|
|
340
|
+
hooks: [
|
|
341
|
+
{
|
|
342
|
+
type: "command",
|
|
343
|
+
command: `${hd}/session-start.sh`,
|
|
344
|
+
timeout: 5,
|
|
345
|
+
},
|
|
346
|
+
],
|
|
347
|
+
},
|
|
348
|
+
],
|
|
321
349
|
PreToolUse: [
|
|
322
350
|
{
|
|
323
351
|
matcher: "Bash",
|
|
324
352
|
hooks: [
|
|
353
|
+
{
|
|
354
|
+
type: "command",
|
|
355
|
+
command: `${hd}/auto-update.sh`,
|
|
356
|
+
timeout: 5,
|
|
357
|
+
},
|
|
325
358
|
{
|
|
326
359
|
type: "command",
|
|
327
360
|
if: "Bash(git push*)",
|
|
@@ -336,6 +369,13 @@ async function main() {
|
|
|
336
369
|
timeout: 15,
|
|
337
370
|
statusMessage: "◆ Syncing tracking...",
|
|
338
371
|
},
|
|
372
|
+
{
|
|
373
|
+
type: "command",
|
|
374
|
+
if: "Bash(vercel --prod*)",
|
|
375
|
+
command: `${hd}/pre-deploy-gate.sh`,
|
|
376
|
+
timeout: 120,
|
|
377
|
+
statusMessage: "◆ Running quality gates...",
|
|
378
|
+
},
|
|
339
379
|
],
|
|
340
380
|
},
|
|
341
381
|
{
|
|
@@ -358,20 +398,6 @@ async function main() {
|
|
|
358
398
|
],
|
|
359
399
|
},
|
|
360
400
|
],
|
|
361
|
-
PostToolUse: [
|
|
362
|
-
{
|
|
363
|
-
matcher: "Bash",
|
|
364
|
-
hooks: [
|
|
365
|
-
{
|
|
366
|
-
type: "command",
|
|
367
|
-
if: "Bash(vercel --prod*)",
|
|
368
|
-
command: `${hd}/pre-deploy-gate.sh`,
|
|
369
|
-
timeout: 120,
|
|
370
|
-
statusMessage: "◆ Running quality gates...",
|
|
371
|
-
},
|
|
372
|
-
],
|
|
373
|
-
},
|
|
374
|
-
],
|
|
375
401
|
PreCompact: [
|
|
376
402
|
{
|
|
377
403
|
matcher: "compact",
|
|
@@ -414,7 +440,7 @@ async function main() {
|
|
|
414
440
|
|
|
415
441
|
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
|
416
442
|
|
|
417
|
-
ok("Hooks: branch-guard, pre-push, env-block, migration-guard, deploy-gate, pre-compact");
|
|
443
|
+
ok("Hooks: session-start, auto-update, branch-guard, pre-push, env-block, migration-guard, deploy-gate, pre-compact");
|
|
418
444
|
ok("Status line + spinner configured");
|
|
419
445
|
ok("Environment variables + permissions");
|
|
420
446
|
|
|
@@ -424,12 +450,13 @@ async function main() {
|
|
|
424
450
|
console.log(`${DIM} ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}`);
|
|
425
451
|
console.log(` ${WHITE}${member.name}${RESET} ${DIM}(${member.role})${RESET}`);
|
|
426
452
|
console.log(` Skills: ${WHITE}${skills.length}${RESET}`);
|
|
427
|
-
|
|
428
|
-
console.log(`
|
|
429
|
-
console.log(`
|
|
430
|
-
console.log(`
|
|
453
|
+
const agentCount = fs.readdirSync(agentsDir).filter(f => f.endsWith('.md')).length;
|
|
454
|
+
console.log(` Agents: ${WHITE}${agentCount}${RESET} ${DIM}(planner, builder, verifier, qa-browser)${RESET}`);
|
|
455
|
+
console.log(` Hooks: ${WHITE}8${RESET} ${DIM}(session-start, auto-update, branch-guard, pre-push, env-block, migration-guard, deploy-gate, pre-compact)${RESET}`);
|
|
456
|
+
console.log(` Rules: ${WHITE}${fs.readdirSync(rulesDir).length}${RESET} ${DIM}(security, frontend, design-reference, deployment)${RESET}`);
|
|
457
|
+
console.log(` Scripts: ${WHITE}2${RESET} ${DIM}(state.js, qualia-ui.js)${RESET}`);
|
|
431
458
|
console.log(` Knowledge: ${WHITE}3${RESET} ${DIM}(patterns, fixes, client prefs)${RESET}`);
|
|
432
|
-
console.log(` Templates: ${WHITE}
|
|
459
|
+
console.log(` Templates: ${WHITE}${fs.readdirSync(tmplDir).length}${RESET}`);
|
|
433
460
|
console.log(` Status line: ${GREEN}✓${RESET}`);
|
|
434
461
|
console.log(` CLAUDE.md: ${GREEN}✓${RESET} ${DIM}(${member.role})${RESET}`);
|
|
435
462
|
|