start-vibing 4.3.3 → 4.4.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.
Files changed (45) hide show
  1. package/package.json +2 -2
  2. package/template/.claude/agents/sd-audit.md +32 -0
  3. package/template/.claude/skills/e2e-audit/DESIGN.md +294 -0
  4. package/template/.claude/skills/e2e-audit/SKILL.md +660 -0
  5. package/template/.claude/skills/e2e-audit/e2e/fixtures/auth.setup.ts +70 -0
  6. package/template/.claude/skills/e2e-audit/e2e/fixtures/auth.ts +21 -0
  7. package/template/.claude/skills/e2e-audit/e2e/fixtures/base.ts +90 -0
  8. package/template/.claude/skills/e2e-audit/e2e/fixtures/storage/.gitkeep +0 -0
  9. package/template/.claude/skills/e2e-audit/e2e/fixtures/storage/admin.json +50 -0
  10. package/template/.claude/skills/e2e-audit/e2e/fixtures/storage/manager.json +50 -0
  11. package/template/.claude/skills/e2e-audit/e2e/fixtures/storage/member.json +50 -0
  12. package/template/.claude/skills/e2e-audit/e2e/fixtures/storage/owner.json +50 -0
  13. package/template/.claude/skills/e2e-audit/e2e/pages/dashboard-admin.page.ts +141 -0
  14. package/template/.claude/skills/e2e-audit/e2e/pages/dashboard-billing.page.ts +47 -0
  15. package/template/.claude/skills/e2e-audit/e2e/pages/dashboard-chat.page.ts +35 -0
  16. package/template/.claude/skills/e2e-audit/e2e/pages/dashboard-home.page.ts +134 -0
  17. package/template/.claude/skills/e2e-audit/e2e/pages/dashboard-integrations.page.ts +334 -0
  18. package/template/.claude/skills/e2e-audit/e2e/pages/dashboard-knowledge.page.ts +30 -0
  19. package/template/.claude/skills/e2e-audit/e2e/pages/dashboard-ontology.page.ts +71 -0
  20. package/template/.claude/skills/e2e-audit/e2e/pages/dashboard-profile.page.ts +38 -0
  21. package/template/.claude/skills/e2e-audit/e2e/pages/dashboard-teams.page.ts +123 -0
  22. package/template/.claude/skills/e2e-audit/e2e/pages/dashboard-transcripts.page.ts +109 -0
  23. package/template/.claude/skills/e2e-audit/e2e/specs/auth/login.spec.ts +59 -0
  24. package/template/.claude/skills/e2e-audit/e2e/specs/dashboard-admin.spec.ts +233 -0
  25. package/template/.claude/skills/e2e-audit/e2e/specs/dashboard-billing.spec.ts +44 -0
  26. package/template/.claude/skills/e2e-audit/e2e/specs/dashboard-chat.spec.ts +50 -0
  27. package/template/.claude/skills/e2e-audit/e2e/specs/dashboard-home.spec.ts +243 -0
  28. package/template/.claude/skills/e2e-audit/e2e/specs/dashboard-integrations.spec.ts +472 -0
  29. package/template/.claude/skills/e2e-audit/e2e/specs/dashboard-knowledge.spec.ts +57 -0
  30. package/template/.claude/skills/e2e-audit/e2e/specs/dashboard-ontology.spec.ts +72 -0
  31. package/template/.claude/skills/e2e-audit/e2e/specs/dashboard-profile.spec.ts +48 -0
  32. package/template/.claude/skills/e2e-audit/e2e/specs/dashboard-teams.spec.ts +247 -0
  33. package/template/.claude/skills/e2e-audit/e2e/specs/dashboard-transcripts.spec.ts +122 -0
  34. package/template/.claude/skills/e2e-audit/e2e/specs/security/headers.spec.ts +39 -0
  35. package/template/.claude/skills/e2e-audit/e2e/specs/security/rbac.spec.ts +92 -0
  36. package/template/.claude/skills/e2e-audit/e2e/specs/security/xss.spec.ts +74 -0
  37. package/template/.claude/skills/e2e-audit/e2e/utils/console-collector.ts +89 -0
  38. package/template/.claude/skills/e2e-audit/e2e/utils/security-helpers.ts +114 -0
  39. package/template/.claude/skills/e2e-audit/e2e/utils/test-data.ts +64 -0
  40. package/template/.claude/skills/e2e-audit/runbook.md +115 -0
  41. package/template/.claude/skills/super-design/SKILL.md +42 -4
  42. package/template/.claude/skills/super-design/references/audit-methodology.md +63 -7
  43. package/template/.claude/skills/super-design/scripts/discover-surfaces.sh +197 -0
  44. package/template/.claude/skills/super-design/scripts/extract-project-rules.sh +240 -0
  45. package/template/.claude/skills/super-design/scripts/verify-audit.sh +34 -1
@@ -0,0 +1,240 @@
1
+ #!/usr/bin/env bash
2
+ # extract-project-rules.sh — parse project FORBIDDEN rules from
3
+ # CLAUDE.md / AGENTS.md / .cursorrules into an authoritative rule
4
+ # source for sd-audit Step 3h.
5
+ #
6
+ # User-owned FORBIDDEN tables ("Use Cards on mobile", "Waterfall data
7
+ # fetching", "Make responsive UI only") are HIGHER-PRIORITY than generic
8
+ # Nielsen/WCAG heuristics because the project owner has already
9
+ # codified them as the right answer for this codebase. sd-audit treats
10
+ # violations as primary findings — NOT as a severity bump or a tag on
11
+ # another finding. If CLAUDE.md says "no cards on mobile" and we see a
12
+ # Card in a mobile flex-col, the rule fires as
13
+ # `project-forbidden-use-cards-on-mobile` with the project's own wording.
14
+ #
15
+ # Output: JSON on stdout
16
+ # {
17
+ # "source_files": ["CLAUDE.md", ".claude/CLAUDE.md"],
18
+ # "rules": [
19
+ # {
20
+ # "raw": "Use Cards on mobile",
21
+ # "reason": "Waste space in flex-col",
22
+ # "slug": "use-cards-on-mobile",
23
+ # "audit_applicable": true,
24
+ # "detector_family": "mobile",
25
+ # "template_id": "M2",
26
+ # "detector_hint": "flag <Card> inside flex-col at viewport ≤ 768"
27
+ # }
28
+ # ]
29
+ # }
30
+ #
31
+ # `audit_applicable: false` means the rule is code-level (e.g. "Files >
32
+ # 400 lines", "Use `any` type", "'use client' at top level") and does
33
+ # NOT produce an audit finding. sd-audit only iterates applicable rules.
34
+ set -euo pipefail
35
+
36
+ log() { printf '[extract-project-rules] %s\n' "$*" >&2; }
37
+
38
+ # Files to scan in order of authority.
39
+ CANDIDATE_FILES=(
40
+ "CLAUDE.md"
41
+ "AGENTS.md"
42
+ "GEMINI.md"
43
+ ".claude/CLAUDE.md"
44
+ ".cursorrules"
45
+ )
46
+
47
+ SOURCE_FILES=()
48
+ for f in "${CANDIDATE_FILES[@]}"; do
49
+ [[ -f "$f" ]] && SOURCE_FILES+=("$f")
50
+ done
51
+
52
+ if [[ ${#SOURCE_FILES[@]} -eq 0 ]]; then
53
+ log "no project rule files found; emitting empty rule set"
54
+ jq -n '{source_files:[],rules:[]}'
55
+ exit 0
56
+ fi
57
+
58
+ # Extract FORBIDDEN table rows. We look for Markdown tables under any
59
+ # heading that contains the word "FORBIDDEN" (case-insensitive). Rows
60
+ # have shape: `| <action> | <reason> |`. We skip header, separator, and
61
+ # empty rows.
62
+ #
63
+ # Implementation: awk state machine — enter "in table" when we see a
64
+ # FORBIDDEN-ish heading followed by a table header; exit when we see a
65
+ # blank line followed by a new heading or the next "---" separator
66
+ # OUTSIDE the table.
67
+ extract_rows() {
68
+ local file="$1"
69
+ awk '
70
+ BEGIN { mode=0; seen_header=0 }
71
+ /^#+[[:space:]]+.*[Ff][Oo][Rr][Bb][Ii][Dd][Dd][Ee][Nn]/ { mode=1; seen_header=0; next }
72
+ # Close on next top-level or section heading when we were inside
73
+ mode == 1 && /^#+[[:space:]]/ && !/[Ff][Oo][Rr][Bb][Ii][Dd][Dd][Ee][Nn]/ { mode=0; seen_header=0; next }
74
+ mode == 1 && /^\|.*\|.*\|/ {
75
+ if (seen_header == 0) { seen_header=1; next }
76
+ # skip separator row
77
+ if ($0 ~ /^\|[[:space:]]*[-]+/) { next }
78
+ # split on | and take cells 1 and 2 (cells 0 and last are empty)
79
+ n = split($0, cells, "|");
80
+ # cells[2] = action, cells[3] = reason (after leading |)
81
+ action = cells[2]; reason = cells[3];
82
+ gsub(/^[[:space:]]+|[[:space:]]+$/, "", action);
83
+ gsub(/^[[:space:]]+|[[:space:]]+$/, "", reason);
84
+ if (action != "" && action !~ /^-+$/ && action !~ /^Action$/i) {
85
+ printf "%s\t%s\n", action, reason;
86
+ }
87
+ }
88
+ ' "$file"
89
+ }
90
+
91
+ # Slugify: lowercase, non-word → dash, collapse, trim.
92
+ slugify() {
93
+ printf '%s' "$1" | tr '[:upper:]' '[:lower:]' | sed -E 's/[^a-z0-9]+/-/g; s/^-+|-+$//g'
94
+ }
95
+
96
+ # Classify a rule into {audit_applicable, detector_family, template_id,
97
+ # detector_hint}. Keyword-based — additive over time.
98
+ #
99
+ # Audit-applicable families:
100
+ # mobile → M1-M15 (cards on mobile, responsive-only, card grid on mobile, etc.)
101
+ # design → V1-V8 (Cards used everywhere, masonry on mobile, etc.)
102
+ # ux → U1-U10 (no loading states, waterfall fetching hits UX)
103
+ # perf → P1-P10 (bundle size, waterfall as perf issue)
104
+ # a11y → A1-A15 (contrast, focus, etc.)
105
+ #
106
+ # Non-audit (code-level, skip): "Files >", "'use client'", "Use any
107
+ # type", "wildcard imports", "skip typecheck", etc.
108
+ classify() {
109
+ local raw="$1"
110
+ local low
111
+ low="$(printf '%s' "$raw" | tr '[:upper:]' '[:lower:]')"
112
+
113
+ # -- code-level (NOT audit-applicable) --
114
+ case "$low" in
115
+ *"files >"*|*"> 400 lines"*|*"> 300 lines"*|*"wildcard icon"*|\
116
+ *"'use client'"*|*"use \`any\`"*|*"use any type"*|\
117
+ *"relative imports"*|*"skip typecheck"*|*"skip lint"*|\
118
+ *"define types in"*|*"@types"*|*"skip docker"*|*"write in non-english"*|\
119
+ *"commit directly to main"*|*"skip code-simplifier"*|\
120
+ *"auto-document"*|*"mix doc types"*|*"leave docs unlinked"*|\
121
+ *"skip claude.md"*|*"use mui"*|*"skip todo"*|*"stack last change"*|\
122
+ *"skip research"*|*"skip superpowers"*|*"skip documenter"*|\
123
+ *"skip planning"*|*"skip domain"*|*"skip cn utility"*|\
124
+ *"skip flow documentation"*|*"waterfall data fetching"*)
125
+ # note: waterfall IS audit-adjacent via perf, but the primary
126
+ # signal is in package code not in rendered UI. Keep as code-level.
127
+ echo "false code-level - -"
128
+ return
129
+ ;;
130
+ esac
131
+
132
+ # -- mobile (M family) --
133
+ case "$low" in
134
+ *"card"*"mobile"*|*"mobile"*"card"*|*"cards on mobile"*|\
135
+ *"masonry grid on mobile"*|*"3d elements on mobile"*)
136
+ echo "true mobile M2 flag <Card>/card components inside vertical stack at viewport ≤ 768"
137
+ return
138
+ ;;
139
+ *"responsive ui only"*|*"responsive only"*|*"make responsive"*)
140
+ echo "true mobile M-distinct check mobile viewport is a distinct layout not a scaled-down desktop"
141
+ return
142
+ ;;
143
+ *"hamburger-only"*|*"no bottom tabs"*|*"bottom nav"*)
144
+ echo "true mobile M1 require bottom tabs on mobile for primary nav"
145
+ return
146
+ ;;
147
+ *"centered modal on mobile"*|*"centered dialog on mobile"*)
148
+ echo "true mobile M6 require bottom-sheet on mobile, not centered dialog"
149
+ return
150
+ ;;
151
+ esac
152
+
153
+ # -- design (V family) --
154
+ case "$low" in
155
+ *"neumorphism"*)
156
+ echo "true design V-neumorphism flag neumorphic styles on form surfaces (accessibility risk)"
157
+ return
158
+ ;;
159
+ *"scroll animations on dashboard"*)
160
+ echo "true design V-scroll flag scroll-triggered animations on dashboard/app routes"
161
+ return
162
+ ;;
163
+ *"mix animation libraries"*)
164
+ echo "true design V-animmix flag presence of multiple animation libs (framer + gsap + lottie)"
165
+ return
166
+ ;;
167
+ esac
168
+
169
+ # -- ux (U family) --
170
+ case "$low" in
171
+ *"skip loading.tsx"*|*"no loading state"*|*"skip skeleton"*)
172
+ echo "true ux U3 flag absence of loading state on data-fetching page"
173
+ return
174
+ ;;
175
+ *"skip empty state"*|*"no empty state"*)
176
+ echo "true ux U4 flag absence of empty state on zero-data views"
177
+ return
178
+ ;;
179
+ esac
180
+
181
+ # -- default: unknown but still emit, detector_family=generic --
182
+ echo "true generic - match rule text against page copy / component names"
183
+ }
184
+
185
+ # Build the rules array.
186
+ rules_tsv=""
187
+ for f in "${SOURCE_FILES[@]}"; do
188
+ rows="$(extract_rows "$f" || true)"
189
+ [[ -z "$rows" ]] && continue
190
+ while IFS=$'\t' read -r action reason; do
191
+ [[ -z "$action" ]] && continue
192
+ cls="$(classify "$action")"
193
+ slug="$(slugify "$action")"
194
+ # pack: raw \t reason \t slug \t applicable \t family \t template \t hint \t source
195
+ IFS=$'\t' read -r applicable family tpl hint <<<"$cls"
196
+ printf '%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n' \
197
+ "$action" "$reason" "$slug" "$applicable" "$family" "$tpl" "$hint" "$f"
198
+ rules_tsv+="1"
199
+ done <<<"$rows"
200
+ done
201
+
202
+ # Emit JSON. jq slurps TSV lines from stdin.
203
+ rules_json="$(
204
+ {
205
+ for f in "${SOURCE_FILES[@]}"; do
206
+ rows="$(extract_rows "$f" || true)"
207
+ [[ -z "$rows" ]] && continue
208
+ while IFS=$'\t' read -r action reason; do
209
+ [[ -z "$action" ]] && continue
210
+ cls="$(classify "$action")"
211
+ slug="$(slugify "$action")"
212
+ IFS=$'\t' read -r applicable family tpl hint <<<"$cls"
213
+ jq -n \
214
+ --arg raw "$action" \
215
+ --arg reason "$reason" \
216
+ --arg slug "$slug" \
217
+ --arg applicable "$applicable" \
218
+ --arg family "$family" \
219
+ --arg tpl "$tpl" \
220
+ --arg hint "$hint" \
221
+ --arg source "$f" \
222
+ '{
223
+ raw: $raw,
224
+ reason: $reason,
225
+ slug: $slug,
226
+ source_file: $source,
227
+ audit_applicable: ($applicable == "true"),
228
+ detector_family: $family,
229
+ template_id: $tpl,
230
+ detector_hint: $hint
231
+ }'
232
+ done <<<"$rows"
233
+ done
234
+ } | jq -s 'unique_by(.slug)'
235
+ )"
236
+
237
+ jq -n \
238
+ --argjson sources "$(printf '%s\n' "${SOURCE_FILES[@]}" | jq -Rn '[inputs]')" \
239
+ --argjson rules "${rules_json:-[]}" \
240
+ '{ source_files: $sources, rules: $rules }'
@@ -54,7 +54,9 @@ while IFS=$'\t' read -r id shot snap; do
54
54
  done
55
55
 
56
56
  # 4. snapshot_quote must appear verbatim in the snapshot.
57
- jq -c '.[]' "$FINDINGS" | while read -r f; do
57
+ # Skipped for meta findings (coverage, craft-summary, project-rule)
58
+ # where evidence is aggregate, not a single DOM quote.
59
+ jq -c '.[] | select(.rule | test("^(audit-coverage-|design-intelligence-craft-summary|modal-coverage-gap|form-coverage-gap|project-forbidden-)") | not)' "$FINDINGS" | while read -r f; do
58
60
  id=$(echo "$f" | jq -r .id)
59
61
  q=$(echo "$f" | jq -r .snapshot_quote)
60
62
  s=$(echo "$f" | jq -r .snapshot_path)
@@ -63,6 +65,37 @@ jq -c '.[]' "$FINDINGS" | while read -r f; do
63
65
  fi
64
66
  done
65
67
 
68
+ # 5. design-intelligence/<slug>_<vp>.json MUST exist for every
69
+ # page × viewport combination in MATRIX. This enforces the
70
+ # 0.7.0 mandatory per-combo craft scoring.
71
+ DIS_DIR="$SESSION_DIR/design-intelligence"
72
+ if [ -d "$DIS_DIR" ]; then
73
+ DIS_COUNT=$(find "$DIS_DIR" -maxdepth 1 -type f -name '*.json' | wc -l)
74
+ if [ "$DIS_COUNT" -lt 1 ]; then
75
+ warn "design-intelligence/ exists but is empty — Step 3g skipped"
76
+ fi
77
+ else
78
+ warn "no design-intelligence/ directory — Step 3g (craft scoring) did not run"
79
+ fi
80
+
81
+ # 6. Viewport quota check: if >= 10 total findings, mobile must be
82
+ # >= 30% unless an explicit audit-coverage-skewed meta finding
83
+ # was emitted (which acknowledges the gap).
84
+ TOTAL=$(jq '[.[] | select(.viewport)] | length' "$FINDINGS")
85
+ if [ "$TOTAL" -ge 10 ]; then
86
+ MOBILE=$(jq '[.[] | select(.viewport == "mobile")] | length' "$FINDINGS")
87
+ COVERAGE_ACK=$(jq '[.[] | select(.rule == "audit-coverage-skewed")] | length' "$FINDINGS")
88
+ # integer math: mobile * 100 / total < 30 means < 30%
89
+ if [ "$COVERAGE_ACK" -eq 0 ] && [ $(( MOBILE * 100 / TOTAL )) -lt 30 ]; then
90
+ warn "mobile viewport is $MOBILE / $TOTAL (< 30%) and no audit-coverage-skewed meta finding was emitted"
91
+ fi
92
+ fi
93
+
94
+ # 7. surfaces.json + project-rules.json should exist (0.7.0 contract).
95
+ # Absence is a warning, not a fatal — allows stale sessions to still verify.
96
+ [ -f "$SESSION_DIR/surfaces.json" ] || warn "missing surfaces.json (Step 1.5 skipped)"
97
+ [ -f "$SESSION_DIR/project-rules.json" ] || warn "missing project-rules.json (Step 1.5 skipped)"
98
+
66
99
  COUNT=$(jq 'length' "$FINDINGS")
67
100
  if [ "$STRICT" -eq 1 ] && [ "$WARNINGS" -gt 0 ]; then
68
101
  echo "STRICT: $COUNT findings verified, $WARNINGS warning(s)" >&2