qualia-framework 2.6.0 → 3.2.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 +64 -0
- package/README.md +103 -30
- package/agents/builder.md +110 -0
- package/agents/planner.md +134 -0
- package/agents/qa-browser.md +186 -0
- package/agents/verifier.md +221 -0
- package/bin/cli.js +336 -531
- package/bin/install.js +570 -0
- package/bin/qualia-ui.js +299 -0
- package/bin/state.js +630 -0
- package/bin/statusline.js +252 -0
- package/guide.md +63 -0
- package/hooks/auto-update.js +139 -0
- package/hooks/branch-guard.js +47 -0
- package/hooks/migration-guard.js +60 -0
- package/hooks/pre-compact.js +32 -0
- package/hooks/pre-deploy-gate.js +110 -0
- package/hooks/pre-push.js +33 -0
- package/hooks/session-start.js +170 -0
- package/package.json +29 -20
- package/rules/design-reference.md +179 -0
- package/rules/frontend.md +126 -0
- package/skills/qualia/SKILL.md +87 -0
- package/skills/qualia-build/SKILL.md +97 -0
- package/skills/qualia-debug/SKILL.md +87 -0
- package/skills/qualia-design/SKILL.md +93 -0
- package/skills/qualia-handoff/SKILL.md +66 -0
- package/skills/qualia-idk/SKILL.md +8 -0
- package/skills/qualia-learn/SKILL.md +88 -0
- package/skills/qualia-new/SKILL.md +323 -0
- package/{framework/skills → skills}/qualia-optimize/SKILL.md +1 -1
- package/skills/qualia-pause/SKILL.md +63 -0
- package/skills/qualia-plan/SKILL.md +101 -0
- package/skills/qualia-polish/SKILL.md +157 -0
- package/skills/qualia-quick/SKILL.md +37 -0
- package/skills/qualia-report/SKILL.md +105 -0
- package/skills/qualia-resume/SKILL.md +49 -0
- package/skills/qualia-review/SKILL.md +76 -0
- package/skills/qualia-ship/SKILL.md +90 -0
- package/skills/qualia-skill-new/SKILL.md +167 -0
- package/skills/qualia-task/SKILL.md +91 -0
- package/skills/qualia-verify/SKILL.md +113 -0
- package/templates/DESIGN.md +137 -0
- package/templates/plan.md +28 -0
- package/templates/project.md +22 -0
- package/templates/state.md +27 -0
- package/templates/tracking.json +20 -0
- package/tests/bin.test.sh +673 -0
- package/tests/hooks.test.sh +315 -0
- package/tests/state.test.sh +535 -0
- package/tests/statusline.test.sh +243 -0
- package/bin/collect-metrics.sh +0 -62
- package/framework/.claudeignore +0 -51
- package/framework/CLAUDE.md +0 -51
- package/framework/MCP_SETUP.md +0 -229
- package/framework/agents/architecture-strategist.md +0 -53
- package/framework/agents/backend-agent.md +0 -150
- package/framework/agents/code-simplicity-reviewer.md +0 -86
- package/framework/agents/frontend-agent.md +0 -111
- package/framework/agents/kieran-typescript-reviewer.md +0 -96
- package/framework/agents/performance-oracle.md +0 -111
- package/framework/agents/qualia-codebase-mapper.md +0 -761
- package/framework/agents/qualia-debugger.md +0 -1204
- package/framework/agents/qualia-executor.md +0 -882
- package/framework/agents/qualia-integration-checker.md +0 -424
- package/framework/agents/qualia-phase-researcher.md +0 -457
- package/framework/agents/qualia-plan-checker.md +0 -700
- package/framework/agents/qualia-planner.md +0 -1245
- package/framework/agents/qualia-project-researcher.md +0 -603
- package/framework/agents/qualia-research-synthesizer.md +0 -200
- package/framework/agents/qualia-roadmapper.md +0 -606
- package/framework/agents/qualia-verifier.md +0 -686
- package/framework/agents/red-team-qa.md +0 -130
- package/framework/agents/security-auditor.md +0 -72
- package/framework/agents/team-orchestrator.md +0 -229
- package/framework/agents/teams/framework-audit-team.md +0 -66
- package/framework/agents/teams/full-stack-team.md +0 -48
- package/framework/agents/teams/optimize-team.md +0 -53
- package/framework/agents/teams/review-team.md +0 -70
- package/framework/agents/teams/ship-team.md +0 -86
- package/framework/agents/test-agent.md +0 -182
- package/framework/hooks/auto-format.sh +0 -54
- package/framework/hooks/block-env-edit.sh +0 -42
- package/framework/hooks/branch-guard.sh +0 -43
- package/framework/hooks/confirm-delete.sh +0 -59
- package/framework/hooks/migration-validate.sh +0 -77
- package/framework/hooks/notification-speak.sh +0 -16
- package/framework/hooks/pre-commit.sh +0 -100
- package/framework/hooks/pre-compact.sh +0 -56
- package/framework/hooks/pre-deploy-gate.sh +0 -160
- package/framework/hooks/qualia-colors.sh +0 -32
- package/framework/hooks/retention-cleanup.sh +0 -62
- package/framework/hooks/save-session-state.sh +0 -185
- package/framework/hooks/session-context-loader.sh +0 -96
- package/framework/hooks/session-learn.sh +0 -32
- package/framework/hooks/skill-announce.sh +0 -123
- package/framework/hooks/tool-error-announce.sh +0 -27
- package/framework/install.ps1 +0 -323
- package/framework/install.sh +0 -313
- package/framework/qualia-framework/VERSION +0 -1
- package/framework/qualia-framework/assets/qualia-logo.png +0 -0
- package/framework/qualia-framework/bin/collect-metrics.sh +0 -67
- package/framework/qualia-framework/bin/generate-report-docx.py +0 -429
- package/framework/qualia-framework/bin/qualia-tools.js +0 -2201
- package/framework/qualia-framework/bin/qualia-tools.test.js +0 -1054
- package/framework/qualia-framework/references/checkpoints.md +0 -775
- package/framework/qualia-framework/references/completion-checklists.md +0 -359
- package/framework/qualia-framework/references/continuation-format.md +0 -249
- package/framework/qualia-framework/references/continuation-prompt.md +0 -97
- package/framework/qualia-framework/references/decimal-phase-calculation.md +0 -65
- package/framework/qualia-framework/references/design-quality.md +0 -56
- package/framework/qualia-framework/references/employee-guide.md +0 -167
- package/framework/qualia-framework/references/git-integration.md +0 -254
- package/framework/qualia-framework/references/git-planning-commit.md +0 -50
- package/framework/qualia-framework/references/model-profile-resolution.md +0 -32
- package/framework/qualia-framework/references/model-profiles.md +0 -73
- package/framework/qualia-framework/references/phase-argument-parsing.md +0 -61
- package/framework/qualia-framework/references/planning-config.md +0 -195
- package/framework/qualia-framework/references/questioning.md +0 -141
- package/framework/qualia-framework/references/tdd.md +0 -263
- package/framework/qualia-framework/references/ui-brand.md +0 -160
- package/framework/qualia-framework/references/verification-patterns.md +0 -612
- package/framework/qualia-framework/templates/DEBUG.md +0 -159
- package/framework/qualia-framework/templates/DESIGN.md +0 -81
- package/framework/qualia-framework/templates/UAT.md +0 -247
- package/framework/qualia-framework/templates/codebase/architecture.md +0 -255
- package/framework/qualia-framework/templates/codebase/concerns.md +0 -310
- package/framework/qualia-framework/templates/codebase/conventions.md +0 -307
- package/framework/qualia-framework/templates/codebase/integrations.md +0 -280
- package/framework/qualia-framework/templates/codebase/stack.md +0 -186
- package/framework/qualia-framework/templates/codebase/structure.md +0 -285
- package/framework/qualia-framework/templates/codebase/testing.md +0 -480
- package/framework/qualia-framework/templates/config.json +0 -35
- package/framework/qualia-framework/templates/context.md +0 -283
- package/framework/qualia-framework/templates/continue-here.md +0 -78
- package/framework/qualia-framework/templates/debug-subagent-prompt.md +0 -91
- package/framework/qualia-framework/templates/discovery.md +0 -146
- package/framework/qualia-framework/templates/lab-notes.md +0 -16
- package/framework/qualia-framework/templates/milestone-archive.md +0 -123
- package/framework/qualia-framework/templates/milestone.md +0 -115
- package/framework/qualia-framework/templates/phase-prompt.md +0 -567
- package/framework/qualia-framework/templates/planner-subagent-prompt.md +0 -117
- package/framework/qualia-framework/templates/project.md +0 -184
- package/framework/qualia-framework/templates/projects/ai-agent.md +0 -156
- package/framework/qualia-framework/templates/projects/mobile-app.md +0 -181
- package/framework/qualia-framework/templates/projects/voice-agent.md +0 -134
- package/framework/qualia-framework/templates/projects/website.md +0 -137
- package/framework/qualia-framework/templates/requirements.md +0 -231
- package/framework/qualia-framework/templates/research-project/ARCHITECTURE.md +0 -204
- package/framework/qualia-framework/templates/research-project/FEATURES.md +0 -147
- package/framework/qualia-framework/templates/research-project/PITFALLS.md +0 -200
- package/framework/qualia-framework/templates/research-project/STACK.md +0 -120
- package/framework/qualia-framework/templates/research-project/SUMMARY.md +0 -170
- package/framework/qualia-framework/templates/research.md +0 -552
- package/framework/qualia-framework/templates/roadmap.md +0 -206
- package/framework/qualia-framework/templates/state.md +0 -179
- package/framework/qualia-framework/templates/summary-complex.md +0 -59
- package/framework/qualia-framework/templates/summary-minimal.md +0 -41
- package/framework/qualia-framework/templates/summary-standard.md +0 -48
- package/framework/qualia-framework/templates/summary.md +0 -246
- package/framework/qualia-framework/templates/user-setup.md +0 -311
- package/framework/qualia-framework/templates/verification-report.md +0 -322
- package/framework/qualia-framework/workflows/add-phase.md +0 -179
- package/framework/qualia-framework/workflows/add-todo.md +0 -157
- package/framework/qualia-framework/workflows/audit-milestone.md +0 -241
- package/framework/qualia-framework/workflows/check-todos.md +0 -176
- package/framework/qualia-framework/workflows/complete-milestone.md +0 -858
- package/framework/qualia-framework/workflows/diagnose-issues.md +0 -219
- package/framework/qualia-framework/workflows/discovery-phase.md +0 -289
- package/framework/qualia-framework/workflows/discuss-phase.md +0 -534
- package/framework/qualia-framework/workflows/execute-phase.md +0 -559
- package/framework/qualia-framework/workflows/execute-plan.md +0 -438
- package/framework/qualia-framework/workflows/help.md +0 -470
- package/framework/qualia-framework/workflows/insert-phase.md +0 -220
- package/framework/qualia-framework/workflows/list-phase-assumptions.md +0 -178
- package/framework/qualia-framework/workflows/map-codebase.md +0 -327
- package/framework/qualia-framework/workflows/new-milestone.md +0 -363
- package/framework/qualia-framework/workflows/new-project.md +0 -982
- package/framework/qualia-framework/workflows/pause-work.md +0 -122
- package/framework/qualia-framework/workflows/plan-milestone-gaps.md +0 -256
- package/framework/qualia-framework/workflows/plan-phase.md +0 -422
- package/framework/qualia-framework/workflows/progress.md +0 -389
- package/framework/qualia-framework/workflows/quick.md +0 -252
- package/framework/qualia-framework/workflows/remove-phase.md +0 -326
- package/framework/qualia-framework/workflows/research-phase.md +0 -74
- package/framework/qualia-framework/workflows/resume-project.md +0 -306
- package/framework/qualia-framework/workflows/set-profile.md +0 -80
- package/framework/qualia-framework/workflows/settings.md +0 -145
- package/framework/qualia-framework/workflows/transition.md +0 -556
- package/framework/qualia-framework/workflows/update.md +0 -197
- package/framework/qualia-framework/workflows/verify-phase.md +0 -195
- package/framework/qualia-framework/workflows/verify-work.md +0 -625
- package/framework/rules/context7.md +0 -14
- package/framework/rules/frontend.md +0 -33
- package/framework/rules/speed.md +0 -23
- package/framework/scripts/__pycache__/say.cpython-314.pyc +0 -0
- package/framework/scripts/apply-retention.sh +0 -120
- package/framework/scripts/bootstrap-pop-os.sh +0 -354
- package/framework/scripts/claude-voice +0 -13
- package/framework/scripts/cleanup.sh +0 -131
- package/framework/scripts/cowork-mode.sh +0 -141
- package/framework/scripts/generate-project-claude-md.sh +0 -153
- package/framework/scripts/load-test-webhook.js +0 -172
- package/framework/scripts/say.py +0 -236
- package/framework/scripts/showcase-video-recorder/ffmpeg-builder.js +0 -167
- package/framework/scripts/showcase-video-recorder/playwright-helpers.js +0 -216
- package/framework/scripts/speak.py +0 -55
- package/framework/scripts/speak.sh +0 -18
- package/framework/scripts/status.sh +0 -138
- package/framework/scripts/sync-to-framework.sh +0 -65
- package/framework/scripts/voice-hotkey.py +0 -227
- package/framework/scripts/voice-input.sh +0 -51
- package/framework/skills/animate/SKILL.md +0 -202
- package/framework/skills/bolder/SKILL.md +0 -144
- package/framework/skills/browser-qa/SKILL.md +0 -536
- package/framework/skills/clarify/SKILL.md +0 -179
- package/framework/skills/client-handoff/SKILL.md +0 -135
- package/framework/skills/collab-onboard/SKILL.md +0 -111
- package/framework/skills/colorize/SKILL.md +0 -170
- package/framework/skills/critique/SKILL.md +0 -126
- package/framework/skills/deep-research/SKILL.md +0 -240
- package/framework/skills/delight/SKILL.md +0 -329
- package/framework/skills/deploy/SKILL.md +0 -261
- package/framework/skills/deploy-verify/SKILL.md +0 -377
- package/framework/skills/deploy-verify/scripts/canary-check.sh +0 -206
- package/framework/skills/deploy-verify/scripts/check-console-errors.js +0 -147
- package/framework/skills/deploy-verify/scripts/check-cwv.js +0 -139
- package/framework/skills/deploy-verify/scripts/project-detect.sh +0 -84
- package/framework/skills/deploy-verify/scripts/verify.sh +0 -548
- package/framework/skills/design-quieter/SKILL.md +0 -130
- package/framework/skills/distill/SKILL.md +0 -149
- package/framework/skills/docs-lookup/SKILL.md +0 -79
- package/framework/skills/fcm-notifications/SKILL.md +0 -125
- package/framework/skills/financial-ledger/SKILL.md +0 -1039
- package/framework/skills/frontend-master/NOTICE.md +0 -4
- package/framework/skills/frontend-master/SKILL.md +0 -127
- package/framework/skills/frontend-master/reference/color-and-contrast.md +0 -132
- package/framework/skills/frontend-master/reference/interaction-design.md +0 -123
- package/framework/skills/frontend-master/reference/motion-design.md +0 -99
- package/framework/skills/frontend-master/reference/responsive-design.md +0 -114
- package/framework/skills/frontend-master/reference/spatial-design.md +0 -100
- package/framework/skills/frontend-master/reference/typography.md +0 -131
- package/framework/skills/frontend-master/reference/ux-writing.md +0 -107
- package/framework/skills/harden/SKILL.md +0 -357
- package/framework/skills/i18n-rtl/SKILL.md +0 -752
- package/framework/skills/learn/SKILL.md +0 -95
- package/framework/skills/memory/SKILL.md +0 -50
- package/framework/skills/mobile-expo/SKILL.md +0 -977
- package/framework/skills/mobile-expo/references/store-checklist.md +0 -550
- package/framework/skills/nestjs-backend/README.md +0 -73
- package/framework/skills/nestjs-backend/SKILL.md +0 -446
- package/framework/skills/nestjs-backend/references/templates.md +0 -1173
- package/framework/skills/normalize/SKILL.md +0 -79
- package/framework/skills/onboard/SKILL.md +0 -242
- package/framework/skills/openrouter-agent/SKILL.md +0 -922
- package/framework/skills/polish/SKILL.md +0 -209
- package/framework/skills/pr/SKILL.md +0 -66
- package/framework/skills/qualia/SKILL.md +0 -199
- package/framework/skills/qualia-add-todo/SKILL.md +0 -68
- package/framework/skills/qualia-audit-milestone/SKILL.md +0 -95
- package/framework/skills/qualia-check-todos/SKILL.md +0 -55
- package/framework/skills/qualia-complete-milestone/SKILL.md +0 -134
- package/framework/skills/qualia-debug/SKILL.md +0 -149
- package/framework/skills/qualia-design/SKILL.md +0 -203
- package/framework/skills/qualia-discuss-phase/SKILL.md +0 -72
- package/framework/skills/qualia-evolve/SKILL.md +0 -200
- package/framework/skills/qualia-execute-phase/SKILL.md +0 -89
- package/framework/skills/qualia-framework-audit/SKILL.md +0 -604
- package/framework/skills/qualia-guide/SKILL.md +0 -32
- package/framework/skills/qualia-help/SKILL.md +0 -114
- package/framework/skills/qualia-idk/SKILL.md +0 -352
- package/framework/skills/qualia-list-phase-assumptions/SKILL.md +0 -67
- package/framework/skills/qualia-new-milestone/SKILL.md +0 -72
- package/framework/skills/qualia-new-project/SKILL.md +0 -232
- package/framework/skills/qualia-pause-work/SKILL.md +0 -96
- package/framework/skills/qualia-plan-milestone-gaps/SKILL.md +0 -57
- package/framework/skills/qualia-plan-phase/SKILL.md +0 -104
- package/framework/skills/qualia-production-check/SKILL.md +0 -0
- package/framework/skills/qualia-progress/SKILL.md +0 -53
- package/framework/skills/qualia-quick/SKILL.md +0 -89
- package/framework/skills/qualia-report/SKILL.md +0 -166
- package/framework/skills/qualia-research-phase/SKILL.md +0 -88
- package/framework/skills/qualia-resume-work/SKILL.md +0 -62
- package/framework/skills/qualia-review/SKILL.md +0 -263
- package/framework/skills/qualia-start/SKILL.md +0 -161
- package/framework/skills/qualia-verify-work/SKILL.md +0 -132
- package/framework/skills/rag/SKILL.md +0 -750
- package/framework/skills/responsive/SKILL.md +0 -231
- package/framework/skills/retro/SKILL.md +0 -284
- package/framework/skills/sakani-conventions/SKILL.md +0 -136
- package/framework/skills/sakani-conventions/evals/evals.json +0 -23
- package/framework/skills/sakani-conventions/references/entities.md +0 -365
- package/framework/skills/sakani-conventions/references/error-codes.md +0 -95
- package/framework/skills/seo-master/SKILL.md +0 -490
- package/framework/skills/seo-master/references/checklist.md +0 -199
- package/framework/skills/seo-master/references/structured-data.md +0 -609
- package/framework/skills/ship/SKILL.md +0 -239
- package/framework/skills/stack-researcher/SKILL.md +0 -215
- package/framework/skills/status/SKILL.md +0 -154
- package/framework/skills/status/scripts/health-check.sh +0 -562
- package/framework/skills/subscription-payments/SKILL.md +0 -250
- package/framework/skills/supabase/SKILL.md +0 -973
- package/framework/skills/supabase/references/templates.md +0 -159
- package/framework/skills/team/SKILL.md +0 -67
- package/framework/skills/test-runner/SKILL.md +0 -202
- package/framework/skills/voice-agent/SKILL.md +0 -1312
- package/framework/skills/zoho-workflow/SKILL.md +0 -51
- package/framework/statusline-command.sh +0 -117
- package/framework/teams/default/inboxes/plan-04.json +0 -9
- package/framework/teams/review-team.md +0 -75
- package/framework/teams/ship-team.md +0 -86
- package/profiles/fawzi.json +0 -16
- package/profiles/hasan.json +0 -16
- package/profiles/moayad.json +0 -16
- package/templates/CLAUDE-owner.md +0 -52
- package/templates/CLAUDE.md.hbs +0 -58
- package/templates/env.claude.template +0 -12
- package/templates/settings.json +0 -172
- package/uninstall.sh +0 -90
- /package/{framework/rules → rules}/deployment.md +0 -0
- /package/{framework/rules → rules}/security.md +0 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// ~/.claude/hooks/pre-deploy-gate.js — quality gates before production deploy.
|
|
3
|
+
// PreToolUse hook on `vercel --prod*` commands. Runs tsc, lint, tests, build,
|
|
4
|
+
// then scans for service_role leaks in client code.
|
|
5
|
+
// Exits 1 to BLOCK deploy. Exits 0 to allow.
|
|
6
|
+
// Cross-platform (Windows/macOS/Linux). No `grep` or `find` — pure Node.
|
|
7
|
+
|
|
8
|
+
const fs = require("fs");
|
|
9
|
+
const path = require("path");
|
|
10
|
+
const { spawnSync } = require("child_process");
|
|
11
|
+
|
|
12
|
+
function runGate(label, cmd, args, { required = true } = {}) {
|
|
13
|
+
const r = spawnSync(cmd, args, {
|
|
14
|
+
stdio: "ignore",
|
|
15
|
+
timeout: 180000,
|
|
16
|
+
shell: process.platform === "win32",
|
|
17
|
+
});
|
|
18
|
+
if (r.status === 0) {
|
|
19
|
+
console.log(` ✓ ${label}`);
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
if (required) {
|
|
23
|
+
console.log(`BLOCKED: ${label} errors. Fix before deploying.`);
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function hasScript(name) {
|
|
30
|
+
try {
|
|
31
|
+
const pkg = JSON.parse(fs.readFileSync("package.json", "utf8"));
|
|
32
|
+
return pkg.scripts && typeof pkg.scripts[name] === "string";
|
|
33
|
+
} catch {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function walk(dir, out = []) {
|
|
39
|
+
if (!fs.existsSync(dir)) return out;
|
|
40
|
+
let entries;
|
|
41
|
+
try {
|
|
42
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
43
|
+
} catch {
|
|
44
|
+
return out;
|
|
45
|
+
}
|
|
46
|
+
for (const e of entries) {
|
|
47
|
+
if (e.name === "node_modules" || e.name.startsWith(".")) continue;
|
|
48
|
+
const full = path.join(dir, e.name);
|
|
49
|
+
if (e.isDirectory()) {
|
|
50
|
+
walk(full, out);
|
|
51
|
+
} else if (/\.(ts|tsx|js|jsx|mjs|cjs)$/.test(e.name)) {
|
|
52
|
+
out.push(full);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return out;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function scanServiceRoleLeaks() {
|
|
59
|
+
const roots = ["app", "components", "src", "pages", "lib"];
|
|
60
|
+
const leaks = [];
|
|
61
|
+
for (const root of roots) {
|
|
62
|
+
for (const file of walk(root)) {
|
|
63
|
+
// Skip server-only files (convention: *.server.ts, server/ dirs)
|
|
64
|
+
if (/\.server\.|[\\/]server[\\/]/.test(file)) continue;
|
|
65
|
+
try {
|
|
66
|
+
const content = fs.readFileSync(file, "utf8");
|
|
67
|
+
if (/service_role/.test(content)) {
|
|
68
|
+
leaks.push(file);
|
|
69
|
+
}
|
|
70
|
+
} catch {}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return leaks;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
console.log("⬢ Pre-deploy gate...");
|
|
77
|
+
|
|
78
|
+
// TypeScript
|
|
79
|
+
if (fs.existsSync("tsconfig.json")) {
|
|
80
|
+
runGate("TypeScript", "npx", ["tsc", "--noEmit"]);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Lint
|
|
84
|
+
if (hasScript("lint")) {
|
|
85
|
+
runGate("Lint", "npm", ["run", "lint"]);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Tests
|
|
89
|
+
if (hasScript("test")) {
|
|
90
|
+
runGate("Tests", "npm", ["test"]);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Build
|
|
94
|
+
if (hasScript("build")) {
|
|
95
|
+
runGate("Build", "npm", ["run", "build"]);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Security: no service_role in client code
|
|
99
|
+
const leaks = scanServiceRoleLeaks();
|
|
100
|
+
if (leaks.length > 0) {
|
|
101
|
+
console.log("BLOCKED: service_role found in client code. Remove before deploying.");
|
|
102
|
+
for (const f of leaks.slice(0, 10)) {
|
|
103
|
+
console.log(` ✗ ${f}`);
|
|
104
|
+
}
|
|
105
|
+
process.exit(1);
|
|
106
|
+
}
|
|
107
|
+
console.log(" ✓ Security");
|
|
108
|
+
console.log("⬢ All gates passed.");
|
|
109
|
+
|
|
110
|
+
process.exit(0);
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// ~/.claude/hooks/pre-push.js — update tracking.json with last commit + timestamp.
|
|
3
|
+
// PreToolUse hook on `git push*` commands. state.js handles phase/status sync;
|
|
4
|
+
// this just stamps the file so the ERP sees fresh commit info on every push.
|
|
5
|
+
// Cross-platform (Windows/macOS/Linux).
|
|
6
|
+
|
|
7
|
+
const fs = require("fs");
|
|
8
|
+
const path = require("path");
|
|
9
|
+
const { spawnSync } = require("child_process");
|
|
10
|
+
|
|
11
|
+
const TRACKING = path.join(".planning", "tracking.json");
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
if (fs.existsSync(TRACKING)) {
|
|
15
|
+
const r = spawnSync("git", ["log", "--oneline", "-1", "--format=%h"], {
|
|
16
|
+
encoding: "utf8",
|
|
17
|
+
timeout: 3000,
|
|
18
|
+
});
|
|
19
|
+
const lastCommit = ((r.stdout || "").trim());
|
|
20
|
+
const now = new Date().toISOString().replace(/\.\d+Z$/, "Z");
|
|
21
|
+
|
|
22
|
+
const t = JSON.parse(fs.readFileSync(TRACKING, "utf8"));
|
|
23
|
+
if (lastCommit) t.last_commit = lastCommit;
|
|
24
|
+
t.last_updated = now;
|
|
25
|
+
fs.writeFileSync(TRACKING, JSON.stringify(t, null, 2) + "\n");
|
|
26
|
+
|
|
27
|
+
spawnSync("git", ["add", TRACKING], { timeout: 3000 });
|
|
28
|
+
}
|
|
29
|
+
} catch (err) {
|
|
30
|
+
process.stderr.write(`WARNING: tracking sync failed: ${err.message}\n`);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
process.exit(0);
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// ~/.claude/hooks/session-start.js — branded context panel on session start.
|
|
3
|
+
// Cross-platform (Windows/macOS/Linux). Zero shell dependencies.
|
|
4
|
+
//
|
|
5
|
+
// CRITICAL: this hook must NEVER exit non-zero. Claude Code treats any non-zero
|
|
6
|
+
// exit from a SessionStart hook as a "hook error" and shows a red banner. The
|
|
7
|
+
// banner is purely informational — we'd rather render nothing than block a
|
|
8
|
+
// session. Every call is wrapped in try/catch and we always exit 0 at the end.
|
|
9
|
+
|
|
10
|
+
const fs = require("fs");
|
|
11
|
+
const path = require("path");
|
|
12
|
+
const os = require("os");
|
|
13
|
+
const { spawnSync } = require("child_process");
|
|
14
|
+
|
|
15
|
+
const _traceStart = Date.now();
|
|
16
|
+
|
|
17
|
+
const HOME = os.homedir();
|
|
18
|
+
const UI = path.join(HOME, ".claude", "bin", "qualia-ui.js");
|
|
19
|
+
const STATE_FILE = path.join(".planning", "STATE.md");
|
|
20
|
+
const CONTINUE_HERE = ".continue-here.md";
|
|
21
|
+
|
|
22
|
+
function runUi(...args) {
|
|
23
|
+
if (!fs.existsSync(UI)) return;
|
|
24
|
+
try {
|
|
25
|
+
spawnSync(process.execPath, [UI, ...args], {
|
|
26
|
+
stdio: "inherit",
|
|
27
|
+
timeout: 3000,
|
|
28
|
+
});
|
|
29
|
+
} catch {}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function getNextCommand() {
|
|
33
|
+
const stateJs = path.join(HOME, ".claude", "bin", "state.js");
|
|
34
|
+
if (!fs.existsSync(stateJs)) return "";
|
|
35
|
+
try {
|
|
36
|
+
const r = spawnSync(process.execPath, [stateJs, "check"], {
|
|
37
|
+
encoding: "utf8",
|
|
38
|
+
timeout: 3000,
|
|
39
|
+
});
|
|
40
|
+
if (!r.stdout) return "";
|
|
41
|
+
const j = JSON.parse(r.stdout);
|
|
42
|
+
return j.next_command || "";
|
|
43
|
+
} catch {
|
|
44
|
+
return "";
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function maybeShowUpdateBanner() {
|
|
49
|
+
// Sticky framework update notification for EMPLOYEEs. Populated by
|
|
50
|
+
// auto-update.js when it detects a newer qualia-framework version on npm.
|
|
51
|
+
// OWNER auto-updates silently, so this file is never created for Fawzi.
|
|
52
|
+
try {
|
|
53
|
+
const notifFile = path.join(HOME, ".claude", ".qualia-update-available.json");
|
|
54
|
+
if (!fs.existsSync(notifFile)) return;
|
|
55
|
+
|
|
56
|
+
const cfg = readConfig();
|
|
57
|
+
// Belt-and-suspenders: even if a stale notification exists, OWNER never sees it.
|
|
58
|
+
if (cfg.role === "OWNER") {
|
|
59
|
+
try { fs.unlinkSync(notifFile); } catch {}
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const notif = JSON.parse(fs.readFileSync(notifFile, "utf8"));
|
|
64
|
+
|
|
65
|
+
// If the user has already updated (cfg.version >= notif.latest), clear the file.
|
|
66
|
+
if (cfg.version && notif.latest) {
|
|
67
|
+
const cmp = (a, b) => {
|
|
68
|
+
const pa = String(a).split(".").map(Number);
|
|
69
|
+
const pb = String(b).split(".").map(Number);
|
|
70
|
+
for (let i = 0; i < 3; i++) {
|
|
71
|
+
if ((pa[i] || 0) > (pb[i] || 0)) return 1;
|
|
72
|
+
if ((pa[i] || 0) < (pb[i] || 0)) return -1;
|
|
73
|
+
}
|
|
74
|
+
return 0;
|
|
75
|
+
};
|
|
76
|
+
if (cmp(cfg.version, notif.latest) >= 0) {
|
|
77
|
+
try { fs.unlinkSync(notifFile); } catch {}
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
runUi("update", notif.current || cfg.version || "?", notif.latest || "?");
|
|
83
|
+
} catch {
|
|
84
|
+
// Never fail the session start.
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function fallbackText() {
|
|
89
|
+
// If qualia-ui.js is missing, emit plain text. Keeps the session informative
|
|
90
|
+
// even on a broken install.
|
|
91
|
+
if (fs.existsSync(STATE_FILE)) {
|
|
92
|
+
try {
|
|
93
|
+
const content = fs.readFileSync(STATE_FILE, "utf8");
|
|
94
|
+
const phase = (content.match(/^Phase:\s*(.+)$/m) || [])[1] || "—";
|
|
95
|
+
const status = (content.match(/^Status:\s*(.+)$/m) || [])[1] || "—";
|
|
96
|
+
console.log(`QUALIA: Project loaded. Phase: ${phase.trim()} | Status: ${status.trim()}`);
|
|
97
|
+
console.log("QUALIA: Run /qualia for next step.");
|
|
98
|
+
} catch {
|
|
99
|
+
console.log("QUALIA: Project detected but STATE.md could not be read.");
|
|
100
|
+
}
|
|
101
|
+
} else if (fs.existsSync(CONTINUE_HERE)) {
|
|
102
|
+
console.log("QUALIA: Handoff file found. Read .continue-here.md to resume.");
|
|
103
|
+
} else {
|
|
104
|
+
console.log("QUALIA: No project detected. Run /qualia-new to start.");
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
try {
|
|
109
|
+
// Sticky update notification — shown before anything else every session
|
|
110
|
+
// until the employee runs `npx qualia-framework@latest install`.
|
|
111
|
+
maybeShowUpdateBanner();
|
|
112
|
+
|
|
113
|
+
if (!fs.existsSync(UI)) {
|
|
114
|
+
fallbackText();
|
|
115
|
+
} else if (fs.existsSync(STATE_FILE)) {
|
|
116
|
+
runUi("banner", "router");
|
|
117
|
+
const next = getNextCommand();
|
|
118
|
+
if (next) {
|
|
119
|
+
console.log("");
|
|
120
|
+
runUi("next", next);
|
|
121
|
+
}
|
|
122
|
+
} else if (fs.existsSync(CONTINUE_HERE)) {
|
|
123
|
+
runUi("banner", "resume");
|
|
124
|
+
runUi("warn", "Previous session found — type /qualia-resume to pick up where you left off");
|
|
125
|
+
console.log("");
|
|
126
|
+
} else {
|
|
127
|
+
// No project — show a welcoming first-run experience
|
|
128
|
+
const config = readConfig();
|
|
129
|
+
const name = config.installed_by || "";
|
|
130
|
+
runUi("banner", "router");
|
|
131
|
+
if (name) {
|
|
132
|
+
console.log(` ${TEAL}Ready when you are, ${name}.${RESET}`);
|
|
133
|
+
}
|
|
134
|
+
console.log("");
|
|
135
|
+
console.log(` ${DIM}Start here:${RESET}`);
|
|
136
|
+
console.log(` ${TEAL}/qualia-new${RESET} ${DIM}Set up a new project${RESET}`);
|
|
137
|
+
console.log(` ${TEAL}/qualia${RESET} ${DIM}What should I do next?${RESET}`);
|
|
138
|
+
console.log(` ${TEAL}/qualia-quick${RESET} ${DIM}Quick fix (skip planning)${RESET}`);
|
|
139
|
+
console.log("");
|
|
140
|
+
}
|
|
141
|
+
} catch {
|
|
142
|
+
// Deliberately silent — hook must never fail
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function readConfig() {
|
|
146
|
+
try {
|
|
147
|
+
return JSON.parse(fs.readFileSync(path.join(HOME, ".claude", ".qualia-config.json"), "utf8"));
|
|
148
|
+
} catch {
|
|
149
|
+
return {};
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function _trace(hookName, result, extra) {
|
|
154
|
+
try {
|
|
155
|
+
const traceDir = path.join(os.homedir(), ".claude", ".qualia-traces");
|
|
156
|
+
if (!fs.existsSync(traceDir)) fs.mkdirSync(traceDir, { recursive: true });
|
|
157
|
+
const entry = {
|
|
158
|
+
hook: hookName,
|
|
159
|
+
result,
|
|
160
|
+
timestamp: new Date().toISOString(),
|
|
161
|
+
duration_ms: Date.now() - _traceStart,
|
|
162
|
+
...extra,
|
|
163
|
+
};
|
|
164
|
+
const file = path.join(traceDir, `${new Date().toISOString().split("T")[0]}.jsonl`);
|
|
165
|
+
fs.appendFileSync(file, JSON.stringify(entry) + "\n");
|
|
166
|
+
} catch {}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
_trace("session-start", "allow");
|
|
170
|
+
process.exit(0);
|
package/package.json
CHANGED
|
@@ -1,33 +1,42 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "qualia-framework",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "Qualia Solutions
|
|
3
|
+
"version": "3.2.0",
|
|
4
|
+
"description": "Claude Code workflow framework by Qualia Solutions. Plan, build, verify, ship.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"qualia-framework": "./bin/cli.js"
|
|
7
7
|
},
|
|
8
|
+
"keywords": [
|
|
9
|
+
"claude-code",
|
|
10
|
+
"claude",
|
|
11
|
+
"ai",
|
|
12
|
+
"framework",
|
|
13
|
+
"workflow",
|
|
14
|
+
"qualia",
|
|
15
|
+
"agents",
|
|
16
|
+
"automation"
|
|
17
|
+
],
|
|
18
|
+
"author": "Qualia Solutions <hello@qualia.solutions>",
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/QualiasolutionsCY/qualia-framework.git"
|
|
23
|
+
},
|
|
24
|
+
"homepage": "https://github.com/QualiasolutionsCY/qualia-framework#readme",
|
|
8
25
|
"scripts": {
|
|
9
|
-
"
|
|
26
|
+
"test": "bash tests/hooks.test.sh && bash tests/state.test.sh && bash tests/bin.test.sh && bash tests/statusline.test.sh"
|
|
10
27
|
},
|
|
11
28
|
"files": [
|
|
12
29
|
"bin/",
|
|
13
|
-
"
|
|
14
|
-
"
|
|
30
|
+
"agents/",
|
|
31
|
+
"hooks/",
|
|
32
|
+
"rules/",
|
|
33
|
+
"skills/",
|
|
15
34
|
"templates/",
|
|
16
|
-
"
|
|
35
|
+
"tests/",
|
|
36
|
+
"CLAUDE.md",
|
|
37
|
+
"guide.md"
|
|
17
38
|
],
|
|
18
39
|
"engines": {
|
|
19
|
-
"node": ">=18
|
|
20
|
-
}
|
|
21
|
-
"repository": {
|
|
22
|
-
"type": "git",
|
|
23
|
-
"url": "git+https://github.com/Qualiasolutions/qualia-framework.git"
|
|
24
|
-
},
|
|
25
|
-
"keywords": [
|
|
26
|
-
"claude-code",
|
|
27
|
-
"qualia",
|
|
28
|
-
"framework",
|
|
29
|
-
"ai-dev"
|
|
30
|
-
],
|
|
31
|
-
"author": "Qualia Solutions",
|
|
32
|
-
"license": "UNLICENSED"
|
|
40
|
+
"node": ">=18"
|
|
41
|
+
}
|
|
33
42
|
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
---
|
|
2
|
+
globs: ["*.tsx", "*.jsx", "*.css", "*.scss"]
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Design Reference — Deep Specs
|
|
6
|
+
|
|
7
|
+
Detailed values for motion, accessibility, and responsive design. Loaded alongside `frontend.md` for frontend work.
|
|
8
|
+
|
|
9
|
+
## Motion Specification
|
|
10
|
+
|
|
11
|
+
### Duration Table
|
|
12
|
+
|
|
13
|
+
| Action | Duration | Easing | Example |
|
|
14
|
+
|--------|----------|--------|---------|
|
|
15
|
+
| Micro-feedback | 100ms | ease-out | Button press, checkbox toggle |
|
|
16
|
+
| Hover/focus | 150ms | ease-out | Color change, underline appear |
|
|
17
|
+
| Small reveal | 200ms | ease-out | Tooltip show, dropdown open |
|
|
18
|
+
| Expand/collapse | 250ms | ease-in-out | Accordion, panel slide |
|
|
19
|
+
| Page element enter | 300ms | cubic-bezier(0, 0, 0.2, 1) | Card fade-in, section reveal |
|
|
20
|
+
| Page transition | 400ms | cubic-bezier(0.4, 0, 0.2, 1) | Route change, modal open |
|
|
21
|
+
| Complex orchestration | 500–800ms | staggered | Page load sequence |
|
|
22
|
+
|
|
23
|
+
### Easing Curves (CSS)
|
|
24
|
+
|
|
25
|
+
```css
|
|
26
|
+
--ease-standard: cubic-bezier(0.4, 0, 0.2, 1); /* General movement */
|
|
27
|
+
--ease-decelerate: cubic-bezier(0, 0, 0.2, 1); /* Enter screen */
|
|
28
|
+
--ease-accelerate: cubic-bezier(0.4, 0, 1, 1); /* Exit screen */
|
|
29
|
+
--ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1); /* Playful bounce */
|
|
30
|
+
--ease-smooth: cubic-bezier(0.25, 0.1, 0.25, 1); /* Subtle shift */
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Stagger Pattern
|
|
34
|
+
|
|
35
|
+
```css
|
|
36
|
+
/* Stagger children on page load */
|
|
37
|
+
@keyframes fadeUp {
|
|
38
|
+
from { opacity: 0; transform: translateY(12px); }
|
|
39
|
+
to { opacity: 1; transform: translateY(0); }
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.stagger > * {
|
|
43
|
+
animation: fadeUp 300ms var(--ease-decelerate) both;
|
|
44
|
+
}
|
|
45
|
+
.stagger > *:nth-child(1) { animation-delay: 0ms; }
|
|
46
|
+
.stagger > *:nth-child(2) { animation-delay: 60ms; }
|
|
47
|
+
.stagger > *:nth-child(3) { animation-delay: 120ms; }
|
|
48
|
+
.stagger > *:nth-child(4) { animation-delay: 180ms; }
|
|
49
|
+
.stagger > *:nth-child(5) { animation-delay: 240ms; }
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Reduced Motion
|
|
53
|
+
|
|
54
|
+
```css
|
|
55
|
+
@media (prefers-reduced-motion: reduce) {
|
|
56
|
+
*, *::before, *::after {
|
|
57
|
+
animation-duration: 0.01ms !important;
|
|
58
|
+
animation-iteration-count: 1 !important;
|
|
59
|
+
transition-duration: 0.01ms !important;
|
|
60
|
+
scroll-behavior: auto !important;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## WCAG AA Checklist
|
|
66
|
+
|
|
67
|
+
### Perceivable
|
|
68
|
+
- [ ] All images have descriptive alt text (decorative: `alt=""` + `aria-hidden="true"`)
|
|
69
|
+
- [ ] Color contrast: 4.5:1 normal text, 3:1 large text (18px+ bold / 24px+)
|
|
70
|
+
- [ ] Color contrast: 3:1 for UI components and graphical objects
|
|
71
|
+
- [ ] Information not conveyed by color alone — icons, text, patterns as supplements
|
|
72
|
+
- [ ] Video/audio: captions or transcripts where applicable
|
|
73
|
+
- [ ] Text resizable to 200% without loss of content
|
|
74
|
+
- [ ] Content reflows at 320px viewport width (no horizontal scroll)
|
|
75
|
+
|
|
76
|
+
### Operable
|
|
77
|
+
- [ ] All functionality available via keyboard (Tab, Enter, Space, Escape, Arrows)
|
|
78
|
+
- [ ] No keyboard traps (except intentional focus traps in modals)
|
|
79
|
+
- [ ] Visible focus indicator: 2px+ ring, contrasting color, no `outline: none` without replacement
|
|
80
|
+
- [ ] Skip navigation link as first focusable element
|
|
81
|
+
- [ ] Touch targets: 44x44px minimum (48x48px recommended)
|
|
82
|
+
- [ ] No content that flashes more than 3 times per second
|
|
83
|
+
- [ ] Page titles are descriptive and unique
|
|
84
|
+
|
|
85
|
+
### Understandable
|
|
86
|
+
- [ ] Form inputs have visible labels (not placeholder-only)
|
|
87
|
+
- [ ] Error messages identify the field and describe the error
|
|
88
|
+
- [ ] Error suggestions explain how to fix the problem
|
|
89
|
+
- [ ] Required fields marked with `aria-required="true"` and visual indicator
|
|
90
|
+
- [ ] Language set: `<html lang="en">`
|
|
91
|
+
- [ ] Consistent navigation across pages
|
|
92
|
+
- [ ] No unexpected context changes on input
|
|
93
|
+
|
|
94
|
+
### Robust
|
|
95
|
+
- [ ] Valid HTML (no duplicate IDs, proper nesting)
|
|
96
|
+
- [ ] ARIA used correctly: `role`, `aria-label`, `aria-describedby`, `aria-expanded`, `aria-hidden`
|
|
97
|
+
- [ ] Dynamic content: `aria-live="polite"` for updates, `aria-live="assertive"` for errors
|
|
98
|
+
- [ ] Custom components have proper roles and keyboard interaction patterns
|
|
99
|
+
|
|
100
|
+
## Responsive Breakpoints
|
|
101
|
+
|
|
102
|
+
### Strategy: Mobile-First with Fluid Scaling
|
|
103
|
+
|
|
104
|
+
```css
|
|
105
|
+
/* Base: mobile (320px–639px) */
|
|
106
|
+
/* sm: 640px+ — large phone / small tablet */
|
|
107
|
+
/* md: 768px+ — tablet */
|
|
108
|
+
/* lg: 1024px+ — laptop */
|
|
109
|
+
/* xl: 1280px+ — desktop */
|
|
110
|
+
/* 2xl: 1536px+ — large desktop */
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Common Patterns
|
|
114
|
+
|
|
115
|
+
| Pattern | Mobile | Tablet | Desktop |
|
|
116
|
+
|---------|--------|--------|---------|
|
|
117
|
+
| Navigation | Hamburger + drawer | Hamburger or condensed | Full horizontal |
|
|
118
|
+
| Grid | 1 column | 2 columns | 3–4 columns |
|
|
119
|
+
| Sidebar | Hidden, overlay | Collapsible | Always visible |
|
|
120
|
+
| Hero | Stacked, full-width | Stacked, padded | Side-by-side |
|
|
121
|
+
| Table | Card view or scroll | Scroll with sticky col | Full table |
|
|
122
|
+
| Modal | Full screen | Centered, 80% width | Centered, max-width |
|
|
123
|
+
| Form | Single column | Single column | Two column for long forms |
|
|
124
|
+
|
|
125
|
+
### Fluid Typography
|
|
126
|
+
|
|
127
|
+
```css
|
|
128
|
+
/* Body */
|
|
129
|
+
font-size: clamp(1rem, 0.5rem + 1.5vw, 1.125rem);
|
|
130
|
+
|
|
131
|
+
/* H1 */
|
|
132
|
+
font-size: clamp(2rem, 1rem + 3vw, 3.75rem);
|
|
133
|
+
|
|
134
|
+
/* H2 */
|
|
135
|
+
font-size: clamp(1.5rem, 0.75rem + 2.25vw, 2.5rem);
|
|
136
|
+
|
|
137
|
+
/* H3 */
|
|
138
|
+
font-size: clamp(1.25rem, 0.75rem + 1.5vw, 1.875rem);
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Fluid Spacing
|
|
142
|
+
|
|
143
|
+
```css
|
|
144
|
+
/* Section padding */
|
|
145
|
+
padding-inline: clamp(1rem, 5vw, 4rem);
|
|
146
|
+
padding-block: clamp(2rem, 8vw, 6rem);
|
|
147
|
+
|
|
148
|
+
/* Component gap */
|
|
149
|
+
gap: clamp(1rem, 3vw, 2rem);
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## React/Next.js Performance (Critical)
|
|
153
|
+
|
|
154
|
+
### Priority 1: Eliminate Waterfalls
|
|
155
|
+
- Fetch data in parallel (`Promise.all`), not sequentially
|
|
156
|
+
- Use Suspense boundaries to stream content progressively
|
|
157
|
+
- Prefetch data on hover/focus for anticipated navigation
|
|
158
|
+
- Colocate data fetching with the component that needs it
|
|
159
|
+
|
|
160
|
+
### Priority 2: Bundle Size
|
|
161
|
+
- Import specific functions, not entire libraries (`import { format } from 'date-fns'`)
|
|
162
|
+
- Avoid barrel files (index.ts re-exports) — import directly from source
|
|
163
|
+
- Use `next/dynamic` for heavy components not needed on initial load
|
|
164
|
+
- Lazy-load below-fold content and non-critical features
|
|
165
|
+
|
|
166
|
+
### Priority 3: Rendering
|
|
167
|
+
- Server Components by default — only add `'use client'` when needed (state, effects, browser APIs)
|
|
168
|
+
- Avoid unnecessary `useEffect` — derive values during render when possible
|
|
169
|
+
- Use CSS `content-visibility: auto` for long scrollable lists
|
|
170
|
+
- Images: `next/image` with proper `width`/`height` to prevent layout shift
|
|
171
|
+
|
|
172
|
+
## Compound Component Patterns
|
|
173
|
+
|
|
174
|
+
When building reusable components:
|
|
175
|
+
- **No boolean prop proliferation** (`isCompact`, `showHeader`, `isRounded`) — use composition instead
|
|
176
|
+
- Compound components: `<Select>`, `<Select.Trigger>`, `<Select.Content>` with shared context
|
|
177
|
+
- Explicit variants: `<Alert.Destructive>` instead of `<Alert isDestructive>`
|
|
178
|
+
- Children over render props: `children` for composition, not `renderHeader`/`renderFooter`
|
|
179
|
+
- React 19: use `use()` instead of `useContext()`, skip `forwardRef` (ref is a regular prop)
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
---
|
|
2
|
+
globs: ["*.tsx", "*.jsx", "*.css", "*.scss", "tailwind.config.*"]
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Frontend Design Standards
|
|
6
|
+
|
|
7
|
+
These are Qualia brand standards — mandatory for every frontend component. Not suggestions.
|
|
8
|
+
|
|
9
|
+
## Typography
|
|
10
|
+
|
|
11
|
+
**Never use:** Inter, Roboto, Arial, Helvetica, system-ui, Space Grotesk (overused by AI).
|
|
12
|
+
|
|
13
|
+
- Pair a distinctive display font with a refined body font
|
|
14
|
+
- Type scale: 12 / 14 / 16 / 18 / 20 / 24 / 30 / 36 / 48 / 60 / 72
|
|
15
|
+
- Body: 16px min, line-height 1.5–1.7
|
|
16
|
+
- Headings: line-height 1.1–1.3, letter-spacing -0.02em for large sizes
|
|
17
|
+
- Weight hierarchy: Regular (400) body, Medium (500) labels, Semibold (600) headings, Bold (700) display
|
|
18
|
+
- Prose max-width: 65ch. Everything else: fluid full-width
|
|
19
|
+
|
|
20
|
+
## Color
|
|
21
|
+
|
|
22
|
+
- Commit to a cohesive palette — define in CSS variables
|
|
23
|
+
- One dominant brand color with sharp accent for CTAs
|
|
24
|
+
- Never: blue-purple gradients, rainbow palettes, gray-on-gray
|
|
25
|
+
- Dark mode: not just inverted — rethink surfaces, reduce contrast slightly
|
|
26
|
+
- Semantic colors: success (green), warning (amber), error (red), info (blue) — always with non-color indicator too
|
|
27
|
+
- All text must meet **WCAG AA** contrast: 4.5:1 normal text, 3:1 large text (18px+ bold or 24px+)
|
|
28
|
+
|
|
29
|
+
## Layout
|
|
30
|
+
|
|
31
|
+
- Full-width layouts — no hardcoded `max-width: 1200px` or `1280px` caps
|
|
32
|
+
- Fluid padding: `clamp(1rem, 5vw, 4rem)` for horizontal, generous vertical
|
|
33
|
+
- 8px spacing grid: 4 / 8 / 12 / 16 / 24 / 32 / 48 / 64 / 96
|
|
34
|
+
- Tight spacing within groups, generous between sections
|
|
35
|
+
- Asymmetry > symmetry. Overlap, diagonal flow, grid-breaking elements when appropriate
|
|
36
|
+
- No card grids — use varied layouts with visual hierarchy
|
|
37
|
+
- No generic hero sections — make them distinctive and purposeful
|
|
38
|
+
|
|
39
|
+
## Motion & Animation
|
|
40
|
+
|
|
41
|
+
- Hover/focus transitions: 150–200ms ease-out
|
|
42
|
+
- Expand/collapse: 200–300ms ease-in-out
|
|
43
|
+
- Page transitions: 300–500ms ease-out
|
|
44
|
+
- Staggered entrance animations: 50–80ms delay between items
|
|
45
|
+
- **Always** respect `prefers-reduced-motion: reduce` — disable non-essential animation
|
|
46
|
+
- Easing: `cubic-bezier(0.4, 0, 0.2, 1)` (standard), `cubic-bezier(0, 0, 0.2, 1)` (decelerate), `cubic-bezier(0.4, 0, 1, 1)` (accelerate)
|
|
47
|
+
- One well-orchestrated page load > scattered micro-interactions
|
|
48
|
+
- CSS-only for HTML projects, Motion library (`motion/react`) for React
|
|
49
|
+
|
|
50
|
+
## States (Every Interactive Element)
|
|
51
|
+
|
|
52
|
+
- **Loading:** Skeleton or spinner on async operations — never a blank void
|
|
53
|
+
- **Empty:** Helpful message + action when lists/data are empty — never "No results"
|
|
54
|
+
- **Error:** User-friendly message + recovery action — never raw error text
|
|
55
|
+
- **Hover:** Visual feedback within 100ms
|
|
56
|
+
- **Focus:** Visible focus ring (2px+ offset, high contrast) — never `outline: none` without replacement
|
|
57
|
+
- **Active/Pressed:** Scale down slightly or color shift
|
|
58
|
+
- **Disabled:** Reduced opacity (0.5) + `cursor: not-allowed` + `aria-disabled`
|
|
59
|
+
|
|
60
|
+
## Accessibility (WCAG AA Minimum)
|
|
61
|
+
|
|
62
|
+
- Semantic HTML: `<nav>`, `<main>`, `<article>`, `<section>`, `<aside>`, `<header>`, `<footer>` — not divs for everything
|
|
63
|
+
- Heading hierarchy: One `<h1>` per page, sequential order (no skipping h2→h4)
|
|
64
|
+
- All images: descriptive `alt` text (or `alt=""` + `aria-hidden` if decorative)
|
|
65
|
+
- All form inputs: visible `<label>` linked via `htmlFor` — not placeholder-only
|
|
66
|
+
- All interactive elements: keyboard accessible (Tab, Enter, Escape, Arrow keys)
|
|
67
|
+
- Touch targets: 44x44px minimum
|
|
68
|
+
- ARIA: use native HTML elements first. Only add ARIA when HTML semantics aren't enough
|
|
69
|
+
- Never rely solely on color to convey information — add icons, text, or patterns
|
|
70
|
+
- Skip link: `<a href="#main" class="sr-only focus:not-sr-only">` on every page
|
|
71
|
+
- Live regions: `aria-live="polite"` for dynamic content updates (toasts, form validation)
|
|
72
|
+
|
|
73
|
+
## Responsive Design
|
|
74
|
+
|
|
75
|
+
- Mobile-first: base styles for mobile, `@media (min-width)` for larger screens
|
|
76
|
+
- Breakpoints: `sm: 640px`, `md: 768px`, `lg: 1024px`, `xl: 1280px`, `2xl: 1536px`
|
|
77
|
+
- Fluid typography: `clamp(1rem, 0.5rem + 1.5vw, 1.25rem)` for body, scale up for headings
|
|
78
|
+
- Stack on mobile, expand on desktop — never force horizontal scroll
|
|
79
|
+
- Test: 320px (small phone), 375px (iPhone), 768px (tablet), 1024px (laptop), 1440px (desktop)
|
|
80
|
+
- Images: `max-width: 100%`, `height: auto`, use `srcset` for responsive images
|
|
81
|
+
- Navigation: hamburger menu on mobile, expanded on desktop
|
|
82
|
+
|
|
83
|
+
## Component Quality
|
|
84
|
+
|
|
85
|
+
- `cursor: pointer` on ALL clickable elements
|
|
86
|
+
- Smooth transitions (150–300ms) on all state changes
|
|
87
|
+
- No emoji as icons — use SVGs or icon libraries
|
|
88
|
+
- Buttons: clear visual hierarchy (primary, secondary, ghost, destructive)
|
|
89
|
+
- Inputs: visible borders, focus rings, error states with `aria-describedby`
|
|
90
|
+
- Links: distinguishable from text (underline or color + another indicator)
|
|
91
|
+
- Modals: trap focus, close on Escape, `aria-modal="true"`, restore focus on close
|
|
92
|
+
- Toast/notifications: `aria-live`, auto-dismiss with adequate time (5s+), dismissible
|
|
93
|
+
|
|
94
|
+
## Anti-Patterns (Kill on Sight)
|
|
95
|
+
|
|
96
|
+
- Card grids where every card looks identical → varied layouts
|
|
97
|
+
- Generic hero with stock photo → distinctive, purposeful hero
|
|
98
|
+
- Blue-purple gradients → brand colors
|
|
99
|
+
- Static pages with no motion → purposeful animation
|
|
100
|
+
- Fixed widths → fluid responsive
|
|
101
|
+
- Gray text on white (#999 on #fff fails WCAG) → proper contrast
|
|
102
|
+
- Placeholder text shipped to production → real content or proper empty states
|
|
103
|
+
- `outline: none` without focus replacement → visible focus indicators
|
|
104
|
+
- `div` soup → semantic HTML
|
|
105
|
+
- Hardcoded colors scattered in JSX → CSS variables or Tailwind config
|
|
106
|
+
|
|
107
|
+
## Design System Integration
|
|
108
|
+
|
|
109
|
+
If `.planning/DESIGN.md` exists in the project, it takes precedence over these defaults.
|
|
110
|
+
Read it before any frontend work. It contains project-specific: palette, typography, spacing, component patterns.
|
|
111
|
+
|
|
112
|
+
## Impeccable Design Skills (global)
|
|
113
|
+
- `/polish` — Final detail pass before shipping
|
|
114
|
+
- `/bolder` — Amplify safe/boring designs
|
|
115
|
+
- `/design-quieter` — Tone down overly aggressive designs
|
|
116
|
+
- `/animate` — Add purposeful micro-interactions
|
|
117
|
+
- `/colorize` — Inject strategic color into monochrome UIs
|
|
118
|
+
- `/clarify` — Fix unclear UX copy, labels, error messages
|
|
119
|
+
- `/critique` — Design director-level review
|
|
120
|
+
- `/distill` — Strip unnecessary complexity
|
|
121
|
+
- `/delight` — Add memorable touches and personality
|
|
122
|
+
- `/harden` — Edge cases, overflow, i18n robustness
|
|
123
|
+
- `/responsive` — Cross-device responsive adaptation
|
|
124
|
+
|
|
125
|
+
### Recommended workflow
|
|
126
|
+
1. Build feature → 2. `/critique` → 3. `/polish` → 4. `/harden` → ship
|