start-vibing 4.0.2 → 4.1.1
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/package.json +1 -1
- package/template/.claude/CLAUDE.md +86 -20
- package/template/.claude/agents/sd-audit.md +197 -0
- package/template/.claude/agents/sd-fix-verify-semantic.md +112 -0
- package/template/.claude/agents/sd-fix-verify-technical.md +36 -0
- package/template/.claude/agents/sd-fix.md +194 -0
- package/template/.claude/agents/sd-research.md +61 -0
- package/template/.claude/agents/sd-synthesis.md +74 -0
- package/template/.claude/commands/super-design.md +15 -0
- package/template/.claude/hooks/super-design-session-start.sh +4 -0
- package/template/.claude/settings.json +14 -0
- package/template/.claude/skills/codebase-knowledge/SKILL.md +145 -0
- package/template/.claude/skills/codebase-knowledge/TEMPLATE.md +35 -0
- package/template/.claude/skills/codebase-knowledge/domains/claude-system.md +93 -0
- package/template/.claude/skills/composition-patterns/SKILL.md +89 -0
- package/template/.claude/skills/docs-tracker/SKILL.md +239 -0
- package/template/.claude/skills/mcp-builder/SKILL.md +236 -0
- package/template/.claude/skills/quality-gate/scripts/check-all.sh +83 -0
- package/template/.claude/skills/react-best-practices/SKILL.md +146 -0
- package/template/.claude/skills/security-scan/reference/owasp-top-10.md +257 -0
- package/template/.claude/skills/security-scan/scripts/scan.py +190 -0
- package/template/.claude/skills/super-design/README.md +37 -0
- package/template/.claude/skills/super-design/SKILL.md +105 -0
- package/template/.claude/skills/super-design/hooks/guard-paths.py +35 -0
- package/template/.claude/skills/super-design/hooks/post-edit-lint.py +57 -0
- package/template/.claude/skills/super-design/references/audit-methodology.md +513 -0
- package/template/.claude/skills/super-design/references/change-detection-playbook.md +1432 -0
- package/template/.claude/skills/super-design/references/design-theory.md +706 -0
- package/template/.claude/skills/super-design/references/fix-agent-playbook.md +118 -0
- package/template/.claude/skills/super-design/references/market-research-playbook.md +773 -0
- package/template/.claude/skills/super-design/references/playwright-mcp-reference.md +1057 -0
- package/template/.claude/skills/super-design/references/skills-subagents-reference.md +784 -0
- package/template/.claude/skills/super-design/references/superpowers-and-distribution.md +136 -0
- package/template/.claude/skills/super-design/scripts/detect-changes.sh +61 -0
- package/template/.claude/skills/super-design/scripts/diff-tokens.sh +13 -0
- package/template/.claude/skills/super-design/scripts/discover-routes.sh +45 -0
- package/template/.claude/skills/super-design/scripts/extract-tokens.mjs +41 -0
- package/template/.claude/skills/super-design/scripts/hash-pages.sh +42 -0
- package/template/.claude/skills/super-design/scripts/validate-state.sh +15 -0
- package/template/.claude/skills/super-design/scripts/verify-audit.sh +19 -0
- package/template/.claude/skills/super-design/templates/audit-state.schema.json +57 -0
- package/template/.claude/skills/super-design/templates/findings.schema.json +57 -0
- package/template/.claude/skills/super-design/templates/fix-history.md.tpl +26 -0
- package/template/.claude/skills/super-design/templates/overview.md.tpl +52 -0
- package/template/.claude/skills/test-coverage/reference/playwright-patterns.md +260 -0
- package/template/.claude/skills/test-coverage/scripts/coverage-check.sh +52 -0
- package/template/.claude/skills/typeui-ant/SKILL.md +133 -0
- package/template/.claude/skills/typeui-application/SKILL.md +128 -0
- package/template/.claude/skills/typeui-artistic/SKILL.md +133 -0
- package/template/.claude/skills/typeui-bento/SKILL.md +127 -0
- package/template/.claude/skills/typeui-bold/SKILL.md +127 -0
- package/template/.claude/skills/typeui-clean/SKILL.md +128 -0
- package/template/.claude/skills/typeui-dashboard/SKILL.md +133 -0
- package/template/.claude/skills/typeui-doodle/SKILL.md +142 -0
- package/template/.claude/skills/typeui-dramatic/SKILL.md +127 -0
- package/template/.claude/skills/typeui-enterprise/SKILL.md +132 -0
- package/template/.claude/skills/typeui-neobrutalism/SKILL.md +127 -0
- package/template/.claude/skills/typeui-paper/SKILL.md +127 -0
- package/template/.claude/skills/ui-ux-audit/QUICK-START.md +450 -0
- package/template/.claude/skills/ui-ux-audit/README.md +470 -0
- package/template/.claude/skills/ui-ux-audit/templates/audit-report.md +591 -0
- package/template/.claude/skills/ui-ux-audit/templates/competitor-analysis.md +363 -0
- package/template/.claude/skills/ui-ux-audit/templates/component-spec.md +491 -0
- package/template/.claude/skills/ui-ux-audit/templates/improvement-recommendation.md +450 -0
- package/template/.claude/skills/web-design-guidelines/SKILL.md +39 -0
- package/template/.claude/skills/webapp-testing/SKILL.md +96 -0
- package/template/.claude/skills/workflow-state/workflow-state.json +77 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# Superpowers framework + private distribution reference — PLACEHOLDER
|
|
2
|
+
|
|
3
|
+
> **This file is a placeholder.** The complete content was delivered as the
|
|
4
|
+
> "Superpowers and Private Claude Skill Distribution: 2026 Playbook" artifact
|
|
5
|
+
> in the conversation history. Paste it here (~25KB).
|
|
6
|
+
|
|
7
|
+
## What the content covers
|
|
8
|
+
|
|
9
|
+
### Part 1 — Jesse Vincent's Superpowers framework
|
|
10
|
+
- What Superpowers actually is (Claude Code plugin, ~14 skills + session-start hook)
|
|
11
|
+
- Distribution via github.com/obra/superpowers + Anthropic marketplace
|
|
12
|
+
- Four stated principles: TDD, systematic over ad-hoc, complexity reduction,
|
|
13
|
+
evidence over claims
|
|
14
|
+
- The pipeline: brainstorming → writing-plans → subagent-driven-development →
|
|
15
|
+
two-stage review → verification-before-completion → finishing-a-development-branch
|
|
16
|
+
- Jesse Vincent's background (Request Tracker, Perl pumpking, K-9 Mail,
|
|
17
|
+
Keyboardio, VaccinateCA, Prime Radiant)
|
|
18
|
+
- Release cadence: v5.0.7 (Mar 31, 2026), last commit Apr 16, 2026
|
|
19
|
+
- Install: `/plugin install superpowers@claude-plugins-official`
|
|
20
|
+
- 355,657 installs shown on claude.com/plugins/superpowers
|
|
21
|
+
- Cross-platform: Cursor, Codex, OpenCode, Gemini CLI, GitHub Copilot CLI
|
|
22
|
+
- Reception: Simon Willison endorsement, benchmark skepticism, 94% PR rejection rate
|
|
23
|
+
- Relationship to Anthropic Agent Skills (complementary, not competing)
|
|
24
|
+
|
|
25
|
+
### Part 2 — Publishing Claude skills privately in 2026
|
|
26
|
+
|
|
27
|
+
#### Anthropic's official distribution layer
|
|
28
|
+
- Skills Directory (Dec 18, 2025) at claude.com/connectors
|
|
29
|
+
- Only partner-gated, no open submission
|
|
30
|
+
- Claude Code plugin marketplace anthropics/claude-plugins-official
|
|
31
|
+
- Reserved marketplace names list
|
|
32
|
+
- Mahesh Murag (PM) quote: "no revenue-sharing arrangements at this time"
|
|
33
|
+
- 3,000+ community upvotes requesting monetization, zero response from Anthropic
|
|
34
|
+
- Claude Marketplace at claude.com/platform/marketplace is procurement, NOT a skill store
|
|
35
|
+
|
|
36
|
+
#### Private marketplace mechanism (code.claude.com/docs/en/plugin-marketplaces)
|
|
37
|
+
Six channels that work today:
|
|
38
|
+
1. Private GitHub repo (GITHUB_TOKEN env)
|
|
39
|
+
2. Private GitLab/Bitbucket/self-hosted git (SSH key pre-loaded)
|
|
40
|
+
3. Self-hosted HTTP JSON (LiteLLM Enterprise reference)
|
|
41
|
+
4. Private npm registry (.npmrc auth)
|
|
42
|
+
5. Container seed (CLAUDE_CODE_PLUGIN_SEED_DIR env)
|
|
43
|
+
6. Managed settings allowlist (strictKnownMarketplaces)
|
|
44
|
+
|
|
45
|
+
Example marketplace.json:
|
|
46
|
+
```json
|
|
47
|
+
{
|
|
48
|
+
"name": "super-design-private",
|
|
49
|
+
"owner": { "name": "Your Agency", "email": "dev@agency.com" },
|
|
50
|
+
"plugins": [
|
|
51
|
+
{ "source": "github", "repo": "your-org/super-design-skill", "ref": "v1.0.0" }
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Install flow:
|
|
57
|
+
```
|
|
58
|
+
/plugin marketplace add your-org/super-design-marketplace
|
|
59
|
+
/plugin install super-design@super-design-marketplace
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
#### Team/Enterprise org-wide skill sharing (Dec 18, 2025)
|
|
63
|
+
- Admin-provisioned org-wide (default-on)
|
|
64
|
+
- Peer-to-peer sharing (off by default)
|
|
65
|
+
- Peer-to-org sharing (off by default)
|
|
66
|
+
- Skills don't sync across surfaces (Claude.ai / API / Claude Code separate)
|
|
67
|
+
- Collision order: enterprise > personal > project > plugin
|
|
68
|
+
|
|
69
|
+
#### Monetization platform comparison
|
|
70
|
+
|
|
71
|
+
| Platform | Fee | Strengths | Weaknesses |
|
|
72
|
+
|---|---|---|---|
|
|
73
|
+
| **Polar.sh** | 4% + $0.40 | MoR; license keys + GitHub benefits auto; best for super-design | Newer platform |
|
|
74
|
+
| **Lemon Squeezy** | 5% + $0.50 | Strong license API | Higher fees; onboarding rejections |
|
|
75
|
+
| **Gumroad** | 10% + $0.50 | Dominant for existing paid skills | 10% painful at scale |
|
|
76
|
+
| **Stripe** | 2.9% + $0.30 | Lowest fees | NOT merchant-of-record; build your own license server |
|
|
77
|
+
| **Paddle** | varies | MoR | Avoid post-2025 FTC settlement friction |
|
|
78
|
+
| **GitHub Sponsors** | 0% | Auto-invite sponsors to private repo | Monthly tiers only, not one-time |
|
|
79
|
+
|
|
80
|
+
#### License-key mechanics in Claude Code
|
|
81
|
+
- Phone-home validation (24h cached)
|
|
82
|
+
- Ed25519-signed offline files (~50 lines using cryptography.hazmat)
|
|
83
|
+
- Encrypted assets (AES-256-GCM)
|
|
84
|
+
- Watermarking via invisible unicode
|
|
85
|
+
- Telemetry keyed on sha256(license_key)
|
|
86
|
+
|
|
87
|
+
#### Existing paid Claude skills (all Gumroad, zero enforcement)
|
|
88
|
+
- Brian Wagner: $9-$49 bundles
|
|
89
|
+
- Aakash Gupta Job Search OS: $49 one-time / $250/year
|
|
90
|
+
- Usama Akram: 300+ skill bundle
|
|
91
|
+
- RAXXO Studios: €5 single, 8-skill bundle
|
|
92
|
+
- Alex McFarland: Plugin Marketplace Builder (Substack)
|
|
93
|
+
- Sahil Lavingia (Gumroad founder): free as visibility play
|
|
94
|
+
|
|
95
|
+
Price anchors: $9-$19 single, $29-$49 bundles, $49-$99 15+ skill systems, $250+/year subscription.
|
|
96
|
+
|
|
97
|
+
#### Legal: license choices for paid distribution
|
|
98
|
+
- **Elastic License 2.0 (RECOMMENDED for super-design)**: 3 short restrictions —
|
|
99
|
+
no hosted reselling, no circumventing license-key, no removing copyright
|
|
100
|
+
- **PolyForm Shield 1.0.0**: source-available on GitHub, no competitor use
|
|
101
|
+
- **PolyForm Internal Use 1.0.0**: read-only eval version
|
|
102
|
+
- **Custom proprietary EULA**: per-organization seat license, no ML training clause
|
|
103
|
+
|
|
104
|
+
Trademark: CLAUDE registered USPTO, use nominative fair-use, include
|
|
105
|
+
"not affiliated with Anthropic" disclaimer.
|
|
106
|
+
|
|
107
|
+
#### Recommended stack for super-design
|
|
108
|
+
Phase 1 (internal-only): private GitHub repo + PolyForm Internal Use +
|
|
109
|
+
`/plugin marketplace add` with GITHUB_TOKEN.
|
|
110
|
+
|
|
111
|
+
Phase 2 (selling to agencies): Polar.sh as merchant-of-record. Product with:
|
|
112
|
+
- License Keys benefit (3-activation limit)
|
|
113
|
+
- GitHub Repository benefit pointing at private repo
|
|
114
|
+
- Optional file-download of super-design.skill ZIP
|
|
115
|
+
|
|
116
|
+
Pricing: $149 one-time per seat OR $29/month.
|
|
117
|
+
|
|
118
|
+
scripts/verify_license.py: 24-hour cached Polar validation pattern (~40 lines Python).
|
|
119
|
+
|
|
120
|
+
Files: LICENSE (Elastic 2.0 verbatim), EULA.md (plain-English addendum),
|
|
121
|
+
README.md with buy → GitHub invite → export SUPER_DESIGN_LICENSE_KEY → use.
|
|
122
|
+
|
|
123
|
+
Telemetry abuse detection via sha256(license_key) pings.
|
|
124
|
+
|
|
125
|
+
#### Deeper moat (if super-design becomes real business)
|
|
126
|
+
Hosted execution: Stripe-billed service running audits on your infrastructure.
|
|
127
|
+
Heuristics and prompts never touch customer's machine. Tabnine/Wallaby
|
|
128
|
+
precedent. Agent37.com positioning as "Gumroad for Claude skills" with
|
|
129
|
+
hosted-runtime + Stripe billing is worth evaluating.
|
|
130
|
+
|
|
131
|
+
## Where super-design uses this
|
|
132
|
+
|
|
133
|
+
- **LICENSE** (Elastic 2.0 verbatim) — see top-level file
|
|
134
|
+
- **EULA.md** (per-organization seat license) — see top-level file
|
|
135
|
+
- **README.md** install instructions use the private-marketplace pattern
|
|
136
|
+
- **Future scripts/verify_license.py** would follow Polar.sh 24h-cache pattern
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Usage: detect-changes.sh <last_sha> [<last_iso>]
|
|
3
|
+
# Emits JSON: { mode, range_start, commits, files, classified }
|
|
4
|
+
set -euo pipefail
|
|
5
|
+
|
|
6
|
+
LAST_SHA="${1:-}"
|
|
7
|
+
LAST_ISO="${2:-}"
|
|
8
|
+
|
|
9
|
+
if [[ -z "$LAST_SHA" ]]; then echo '{"error":"missing last_sha"}'; exit 2; fi
|
|
10
|
+
if ! git rev-parse --git-dir >/dev/null 2>&1; then echo '{"error":"not-a-git-repo"}'; exit 3; fi
|
|
11
|
+
|
|
12
|
+
if git rev-parse --verify --quiet "${LAST_SHA}^{commit}" >/dev/null; then
|
|
13
|
+
if git merge-base --is-ancestor "$LAST_SHA" HEAD; then RANGE_START="$LAST_SHA"
|
|
14
|
+
else RANGE_START="$(git merge-base HEAD "$LAST_SHA" 2>/dev/null || echo "")"; fi
|
|
15
|
+
else RANGE_START=""; fi
|
|
16
|
+
|
|
17
|
+
if [[ -z "$RANGE_START" ]]; then
|
|
18
|
+
if [[ -n "$LAST_ISO" ]]; then
|
|
19
|
+
FILES="$(git log --since="$LAST_ISO" --name-only --pretty=format: 2>/dev/null | sort -u | sed '/^$/d' || true)"
|
|
20
|
+
COMMITS="$(git log --since="$LAST_ISO" --pretty=format:'%H|%s|%an|%aI' 2>/dev/null || true)"
|
|
21
|
+
MODE="since-time"
|
|
22
|
+
else echo '{"error":"lost-anchor-no-fallback-time"}'; exit 4; fi
|
|
23
|
+
else
|
|
24
|
+
FILES="$(git diff --name-only "${RANGE_START}..HEAD" \
|
|
25
|
+
-- ':!*.lock' ':!package-lock.json' ':!pnpm-lock.yaml' ':!yarn.lock' \
|
|
26
|
+
':!.github/**' ':!**/*.test.*' ':!**/*.spec.*' ':!**/*.stories.*' | sort -u)"
|
|
27
|
+
COMMITS="$(git log --no-merges --pretty=format:'%H|%s|%an|%aI' "${RANGE_START}..HEAD" 2>/dev/null || true)"
|
|
28
|
+
MODE="sha-range"
|
|
29
|
+
fi
|
|
30
|
+
|
|
31
|
+
declare -A CLASSIFIED
|
|
32
|
+
while IFS= read -r p; do
|
|
33
|
+
[[ -z "$p" ]] && continue
|
|
34
|
+
case "$p" in
|
|
35
|
+
tailwind.config.*|*.tokens.json|styles/tokens.css|styles/theme.css) CLASSIFIED[tokens]+="$p,";;
|
|
36
|
+
components/*|src/components/*|app/_components/*) CLASSIFIED[components]+="$p,";;
|
|
37
|
+
app/*/page.*|app/page.*|app/*/route.*|app/route.*|pages/*|src/pages/*|app/routes/*|src/routes/*) CLASSIFIED[routes]+="$p,";;
|
|
38
|
+
public/*|src/assets/*|assets/*) CLASSIFIED[imagery]+="$p,";;
|
|
39
|
+
package.json) CLASSIFIED[deps]+="$p,";;
|
|
40
|
+
references/design-theory.md|references/market-analysis.md) CLASSIFIED[theory]+="$p,";;
|
|
41
|
+
*.md|*.mdx) CLASSIFIED[content]+="$p,";;
|
|
42
|
+
*) CLASSIFIED[other]+="$p,";;
|
|
43
|
+
esac
|
|
44
|
+
done <<< "$FILES"
|
|
45
|
+
|
|
46
|
+
jq -Rn --arg mode "$MODE" --arg range_start "$RANGE_START" --arg last_iso "$LAST_ISO" \
|
|
47
|
+
--arg tokens "${CLASSIFIED[tokens]:-}" --arg components "${CLASSIFIED[components]:-}" \
|
|
48
|
+
--arg routes "${CLASSIFIED[routes]:-}" --arg imagery "${CLASSIFIED[imagery]:-}" \
|
|
49
|
+
--arg deps "${CLASSIFIED[deps]:-}" --arg theory "${CLASSIFIED[theory]:-}" \
|
|
50
|
+
--arg content "${CLASSIFIED[content]:-}" \
|
|
51
|
+
--argjson files "$(printf '%s\n' "$FILES" | jq -R . | jq -s .)" \
|
|
52
|
+
--argjson commits "$(printf '%s\n' "$COMMITS" | jq -R . | jq -s .)" '
|
|
53
|
+
def tolist(s): s | split(",") | map(select(length>0));
|
|
54
|
+
{mode:$mode, range_start:$range_start, since_iso:$last_iso,
|
|
55
|
+
commits:$commits, files:$files,
|
|
56
|
+
classified: {
|
|
57
|
+
tokens: tolist($tokens), components: tolist($components),
|
|
58
|
+
routes: tolist($routes), imagery: tolist($imagery),
|
|
59
|
+
deps: tolist($deps), theory: tolist($theory), content: tolist($content)
|
|
60
|
+
}
|
|
61
|
+
}'
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
PREV="${1:?usage: diff-tokens.sh <prev> <curr>}"
|
|
4
|
+
CURR="${2:?usage: diff-tokens.sh <prev> <curr>}"
|
|
5
|
+
jq -n --slurpfile a "$PREV" --slurpfile b "$CURR" '
|
|
6
|
+
($a[0] // {}) as $before | ($b[0] // {}) as $after |
|
|
7
|
+
{
|
|
8
|
+
added: [$after | to_entries[] | select(.key as $k | ($before | has($k)) | not) | .key],
|
|
9
|
+
removed: [$before | to_entries[] | select(.key as $k | ($after | has($k)) | not) | .key],
|
|
10
|
+
modified: [$after | to_entries[] |
|
|
11
|
+
select(.key as $k | ($before | has($k)) and (.value != $before[$k])) |
|
|
12
|
+
{ key: .key, before: $before[.key], after: .value }]
|
|
13
|
+
}'
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
detect_framework() {
|
|
5
|
+
if [[ -f next.config.js || -f next.config.ts || -f next.config.mjs ]]; then echo "next"
|
|
6
|
+
elif [[ -f remix.config.js || -d app/routes ]]; then echo "remix"
|
|
7
|
+
elif [[ -f svelte.config.js && -d src/routes ]]; then echo "sveltekit"
|
|
8
|
+
elif [[ -f astro.config.mjs || -f astro.config.ts ]]; then echo "astro"
|
|
9
|
+
elif [[ -f nuxt.config.ts || -f nuxt.config.js ]]; then echo "nuxt"
|
|
10
|
+
elif [[ -f app.config.ts && -d src/routes ]]; then echo "solid-start"
|
|
11
|
+
elif [[ -f gatsby-config.js || -f gatsby-config.ts ]]; then echo "gatsby"
|
|
12
|
+
elif [[ -f angular.json ]]; then echo "angular"
|
|
13
|
+
else echo "unknown"; fi
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
FW="$(detect_framework)"
|
|
17
|
+
case "$FW" in
|
|
18
|
+
next)
|
|
19
|
+
APP="$(find app src/app -type f \( -name 'page.tsx' -o -name 'page.ts' -o -name 'page.jsx' -o -name 'page.js' -o -name 'page.md' -o -name 'page.mdx' -o -name 'route.ts' -o -name 'route.js' \) 2>/dev/null \
|
|
20
|
+
| sed -E 's|(^|/)(app|src/app)/||; s|/page\.[a-z]+$||; s|/route\.[a-z]+$||; s|^$|/|' \
|
|
21
|
+
| sed -E 's|\([^)]+\)/||g; /(^|\/)_/d' | sort -u || true)"
|
|
22
|
+
PG="$(find pages src/pages -type f \( -name '*.tsx' -o -name '*.ts' -o -name '*.jsx' -o -name '*.js' -o -name '*.md' -o -name '*.mdx' \) 2>/dev/null \
|
|
23
|
+
| grep -vE '(^|/)(pages|src/pages)/(_app|_document|_error|404|500|api/)' \
|
|
24
|
+
| sed -E 's|(^|/)(pages|src/pages)/||; s|\.(tsx|ts|jsx|js|md|mdx)$||; s|index$||' | sort -u || true)"
|
|
25
|
+
printf '%s\n%s\n' "$APP" "$PG" | awk 'NF' | sed -E 's|^|/|; s|//|/|g' | sort -u | jq -Rn '[inputs]';;
|
|
26
|
+
sveltekit)
|
|
27
|
+
find src/routes -type f -name '+page.svelte' 2>/dev/null \
|
|
28
|
+
| sed -E 's|^src/routes||; s|/\+page\.svelte$||; s|\([^)]+\)/||g' \
|
|
29
|
+
| awk 'NF==0 {print "/"; next} {print}' | sort -u | jq -Rn '[inputs]';;
|
|
30
|
+
astro)
|
|
31
|
+
find src/pages -type f \( -name '*.astro' -o -name '*.md' -o -name '*.mdx' \) 2>/dev/null \
|
|
32
|
+
| sed -E 's|^src/pages||; s|\.(astro|md|mdx)$||; s|/index$||' | sort -u | jq -Rn '[inputs]';;
|
|
33
|
+
nuxt)
|
|
34
|
+
find pages app/pages -type f -name '*.vue' 2>/dev/null \
|
|
35
|
+
| sed -E 's|^(app/)?pages||; s|\.vue$||; s|/index$||' | sort -u | jq -Rn '[inputs]';;
|
|
36
|
+
remix)
|
|
37
|
+
find app/routes -type f \( -name '*.tsx' -o -name '*.ts' -o -name '*.jsx' -o -name '*.js' -o -name '*.md' -o -name '*.mdx' \) 2>/dev/null \
|
|
38
|
+
| sed -E 's|^app/routes/||; s|\.(tsx|ts|jsx|js|md|mdx)$||; s|\.|/|g; s|_index$||; s|^|/|' \
|
|
39
|
+
| sort -u | jq -Rn '[inputs]';;
|
|
40
|
+
solid-start)
|
|
41
|
+
find src/routes -type f \( -name '*.tsx' -o -name '*.ts' -o -name '*.jsx' -o -name '*.js' \) 2>/dev/null \
|
|
42
|
+
| sed -E 's|^src/routes||; s|\.(tsx|ts|jsx|js)$||; s|/index$||; s|\([^)]+\)/||g' \
|
|
43
|
+
| sort -u | jq -Rn '[inputs]';;
|
|
44
|
+
*) echo '[]';;
|
|
45
|
+
esac
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { pathToFileURL } from "node:url";
|
|
5
|
+
|
|
6
|
+
const out = {};
|
|
7
|
+
const tailwindConfigs = ["tailwind.config.ts", "tailwind.config.js", "tailwind.config.mjs", "tailwind.config.cjs"];
|
|
8
|
+
for (const candidate of tailwindConfigs) {
|
|
9
|
+
if (fs.existsSync(candidate)) {
|
|
10
|
+
try {
|
|
11
|
+
const { default: resolveConfig } = await import("tailwindcss/resolveConfig");
|
|
12
|
+
const cfg = (await import(pathToFileURL(path.resolve(candidate)).href)).default;
|
|
13
|
+
const resolved = resolveConfig(cfg);
|
|
14
|
+
flatten(resolved.theme, "tw", out);
|
|
15
|
+
} catch (e) { out[`_error_${candidate}`] = String(e.message || e); }
|
|
16
|
+
break;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
try {
|
|
20
|
+
const postcss = (await import("postcss")).default;
|
|
21
|
+
const cssCandidates = ["styles/globals.css","src/styles/globals.css","app/globals.css","styles/theme.css","src/app/globals.css"];
|
|
22
|
+
for (const css of cssCandidates) {
|
|
23
|
+
if (!fs.existsSync(css)) continue;
|
|
24
|
+
const source = fs.readFileSync(css, "utf8");
|
|
25
|
+
const root = postcss.parse(source);
|
|
26
|
+
root.walkAtRules("theme", at => { at.walkDecls(/^--/, d => { out[`css:${d.prop}`] = d.value.trim(); }); });
|
|
27
|
+
root.walkRules(":root", rule => { rule.walkDecls(/^--/, d => { out[`css:${d.prop}`] = d.value.trim(); }); });
|
|
28
|
+
}
|
|
29
|
+
} catch (e) { out._postcss_error = String(e.message || e); }
|
|
30
|
+
|
|
31
|
+
console.log(JSON.stringify(out, null, 2));
|
|
32
|
+
|
|
33
|
+
function flatten(obj, prefix, acc) {
|
|
34
|
+
if (obj == null) return;
|
|
35
|
+
if (typeof obj !== "object") { acc[prefix] = String(obj); return; }
|
|
36
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
37
|
+
const key = `${prefix}.${k}`;
|
|
38
|
+
if (v && typeof v === "object" && !Array.isArray(v)) flatten(v, key, acc);
|
|
39
|
+
else acc[key] = Array.isArray(v) ? v.join(",") : String(v);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Usage: hash-pages.sh <urls_file>
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
URLS="${1:?usage: hash-pages.sh <urls_file>}"
|
|
5
|
+
OUT_DIR="${OUT_DIR:-docs/super-design/.cache/hashes}"
|
|
6
|
+
mkdir -p "$OUT_DIR"
|
|
7
|
+
|
|
8
|
+
URLS="$URLS" OUT_DIR="$OUT_DIR" node --experimental-vm-modules <<'JS'
|
|
9
|
+
import { chromium } from "playwright";
|
|
10
|
+
import { createHash } from "node:crypto";
|
|
11
|
+
import { readFileSync, writeFileSync } from "node:fs";
|
|
12
|
+
|
|
13
|
+
const urlsFile = process.env.URLS;
|
|
14
|
+
const outDir = process.env.OUT_DIR;
|
|
15
|
+
const urls = readFileSync(urlsFile, "utf8").split("\n").map(s => s.trim()).filter(Boolean);
|
|
16
|
+
const browser = await chromium.launch();
|
|
17
|
+
const ctx = await browser.newContext({
|
|
18
|
+
viewport: { width: 1280, height: 800 }, reducedMotion: "reduce", deviceScaleFactor: 1,
|
|
19
|
+
});
|
|
20
|
+
const page = await ctx.newPage();
|
|
21
|
+
const sha = s => createHash("sha256").update(s).digest("hex");
|
|
22
|
+
const results = [];
|
|
23
|
+
for (const url of urls) {
|
|
24
|
+
try {
|
|
25
|
+
await page.goto(url, { waitUntil: "networkidle", timeout: 30000 });
|
|
26
|
+
const html = (await page.content()).replace(/\s+/g, " ").trim();
|
|
27
|
+
const dom = await page.evaluate(() => {
|
|
28
|
+
const V = new Set(["nonce","data-timestamp","data-reactid","data-next-hydrate"]);
|
|
29
|
+
const walk = n => n.nodeType !== 1 ? "" :
|
|
30
|
+
`<${n.tagName.toLowerCase()}[${[...n.attributes].filter(a=>!V.has(a.name))
|
|
31
|
+
.map(a=>`${a.name}=${a.value}`).sort().join(",")}]${[...n.childNodes].map(walk).join("")}>`;
|
|
32
|
+
return walk(document.documentElement);
|
|
33
|
+
});
|
|
34
|
+
const buf = await page.screenshot({ fullPage: true, animations: "disabled", caret: "hide" });
|
|
35
|
+
results.push({ url, html_hash: "sha256:" + sha(html),
|
|
36
|
+
dom_structure_hash: "sha256:" + sha(dom), screenshot_hash: "sha256:" + sha(buf) });
|
|
37
|
+
} catch (e) { results.push({ url, error: String(e.message || e) }); }
|
|
38
|
+
}
|
|
39
|
+
writeFileSync(outDir + "/hashes.json", JSON.stringify(results, null, 2));
|
|
40
|
+
await browser.close();
|
|
41
|
+
console.log(JSON.stringify({ count: results.length, path: outDir + "/hashes.json" }));
|
|
42
|
+
JS
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
STATE="${1:-docs/super-design/.audit-state.json}"
|
|
4
|
+
if [[ ! -f "$STATE" ]]; then echo '{"status":"missing"}'; exit 2; fi
|
|
5
|
+
jq -e '
|
|
6
|
+
(.schema_version | type == "string") and
|
|
7
|
+
(.last_audit_at | fromdateiso8601 | . > 0) and
|
|
8
|
+
(.git_sha_at_audit | test("^[0-9a-f]{7,64}$")) and
|
|
9
|
+
(.skill_version | type == "string") and
|
|
10
|
+
(.tools | type == "object")
|
|
11
|
+
' "$STATE" >/dev/null 2>&1 || { echo '{"status":"corrupt"}'; exit 2; }
|
|
12
|
+
AGE_DAYS=$(( ( $(date -u +%s) - $(jq -r '.last_audit_at | fromdateiso8601' "$STATE") ) / 86400 ))
|
|
13
|
+
if (( AGE_DAYS > 180 )); then echo "{\"status\":\"stale-force-full\",\"age_days\":$AGE_DAYS}"; exit 1
|
|
14
|
+
elif (( AGE_DAYS > 90 )); then echo "{\"status\":\"stale-refresh-research\",\"age_days\":$AGE_DAYS}"; exit 1
|
|
15
|
+
else echo "{\"status\":\"fresh\",\"age_days\":$AGE_DAYS}"; exit 0; fi
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
SESSION_DIR="${1:?usage: verify-audit.sh <session_dir>}"
|
|
4
|
+
FINDINGS="$SESSION_DIR/findings.json"
|
|
5
|
+
if [[ ! -f "$FINDINGS" ]]; then echo "FATAL: no findings.json at $FINDINGS" >&2; exit 2; fi
|
|
6
|
+
|
|
7
|
+
jq -r '.[] | [.id, .screenshot_path, .snapshot_path] | @tsv' "$FINDINGS" | while IFS=$'\t' read -r id shot snap; do
|
|
8
|
+
if [[ ! -s "$shot" ]]; then echo "FAIL $id: missing/empty screenshot $shot" >&2; exit 1; fi
|
|
9
|
+
if [[ ! -s "$snap" ]]; then echo "FAIL $id: missing/empty snapshot $snap" >&2; exit 1; fi
|
|
10
|
+
done
|
|
11
|
+
|
|
12
|
+
jq -c '.[]' "$FINDINGS" | while read -r f; do
|
|
13
|
+
id=$(echo "$f" | jq -r .id)
|
|
14
|
+
q=$(echo "$f" | jq -r .snapshot_quote)
|
|
15
|
+
s=$(echo "$f" | jq -r .snapshot_path)
|
|
16
|
+
if ! grep -qF "$q" "$s"; then echo "FAIL $id: quote not found verbatim in $s" >&2; exit 1; fi
|
|
17
|
+
done
|
|
18
|
+
|
|
19
|
+
echo "OK: $(jq 'length' "$FINDINGS") findings verified"
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "super-design/audit-state.schema.json",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"required": ["schema_version","skill_version","last_audit_at","git_sha_at_audit","theory_doc_sha","tools","pages_audited","findings_counts"],
|
|
6
|
+
"properties": {
|
|
7
|
+
"schema_version": { "type": "string", "pattern": "^\\d+\\.\\d+\\.\\d+$" },
|
|
8
|
+
"skill_version": { "type": "string" },
|
|
9
|
+
"last_audit_at": { "type": "string", "format": "date-time" },
|
|
10
|
+
"git_sha_at_audit": { "type": "string", "pattern": "^[0-9a-f]{7,64}$" },
|
|
11
|
+
"git_branch": { "type": "string" },
|
|
12
|
+
"is_shallow_clone": { "type": "boolean" },
|
|
13
|
+
"theory_doc_sha": { "type": "string" },
|
|
14
|
+
"market_analysis_sha": { "type": "string" },
|
|
15
|
+
"tools": { "type": "object", "additionalProperties": { "type": "string" } },
|
|
16
|
+
"framework": {
|
|
17
|
+
"type": "object",
|
|
18
|
+
"properties": {
|
|
19
|
+
"name": { "type": "string" },
|
|
20
|
+
"router": { "type": "string" },
|
|
21
|
+
"version": { "type": "string" }
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"route_map": { "type": "array", "items": { "type": "string" } },
|
|
25
|
+
"pages_audited": {
|
|
26
|
+
"type": "array",
|
|
27
|
+
"items": {
|
|
28
|
+
"type": "object",
|
|
29
|
+
"required": ["url","last_audited"],
|
|
30
|
+
"properties": {
|
|
31
|
+
"url": { "type": "string" },
|
|
32
|
+
"route_file": { "type": "string" },
|
|
33
|
+
"html_hash": { "type": "string" },
|
|
34
|
+
"dom_structure_hash": { "type": "string" },
|
|
35
|
+
"viewport_hashes": { "type": "object" },
|
|
36
|
+
"last_audited": { "type": "string", "format": "date-time" },
|
|
37
|
+
"findings_ids": { "type": "array", "items": { "type": "string" } }
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"components": { "type": "object", "additionalProperties": { "type": "string" } },
|
|
42
|
+
"token_hash": { "type": "string" },
|
|
43
|
+
"import_graph_sha": { "type": "string" },
|
|
44
|
+
"findings_counts": {
|
|
45
|
+
"type": "object",
|
|
46
|
+
"required": ["blockers","high","medium","nitpicks"],
|
|
47
|
+
"properties": {
|
|
48
|
+
"blockers": { "type": "integer" },
|
|
49
|
+
"high": { "type": "integer" },
|
|
50
|
+
"medium": { "type": "integer" },
|
|
51
|
+
"nitpicks": { "type": "integer" }
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
"research_at": { "type": "string", "format": "date-time" },
|
|
55
|
+
"ignored_paths": { "type": "array", "items": { "type": "string" } }
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "super-design/findings.schema.json",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"required": ["session_id", "findings"],
|
|
6
|
+
"properties": {
|
|
7
|
+
"session_id": { "type": "string" },
|
|
8
|
+
"findings": {
|
|
9
|
+
"type": "array",
|
|
10
|
+
"items": {
|
|
11
|
+
"type": "object",
|
|
12
|
+
"required": ["id","category","rule","impact","risk_for_fix","files_affected","dom_selector","page_url","viewport","screenshot_path","snapshot_path","snapshot_quote","computed_style_excerpt","severity","finding"],
|
|
13
|
+
"properties": {
|
|
14
|
+
"id": { "type": "string", "pattern": "^F-\\d{4,}$" },
|
|
15
|
+
"category": { "enum": ["a11y","design","ux","perf","baymard","heuristic"] },
|
|
16
|
+
"rule": { "type": "string" },
|
|
17
|
+
"wcag_criterion": { "type": "string" },
|
|
18
|
+
"nielsen_heuristic": { "type": "string" },
|
|
19
|
+
"impact": { "enum": ["minor","moderate","serious","critical"] },
|
|
20
|
+
"severity": { "type": "integer", "minimum": 0, "maximum": 4 },
|
|
21
|
+
"risk_for_fix": { "enum": ["TRIVIAL","LOW","MEDIUM","HIGH"] },
|
|
22
|
+
"files_affected": { "type": "array", "items": { "type": "string" } },
|
|
23
|
+
"page_url": { "type": "string" },
|
|
24
|
+
"viewport": {
|
|
25
|
+
"type": "object",
|
|
26
|
+
"required": ["name","w","h"],
|
|
27
|
+
"properties": {
|
|
28
|
+
"name": { "type": "string" },
|
|
29
|
+
"w": { "type": "integer" },
|
|
30
|
+
"h": { "type": "integer" }
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"screenshot_path": { "type": "string" },
|
|
34
|
+
"snapshot_path": { "type": "string" },
|
|
35
|
+
"snapshot_quote": { "type": "string" },
|
|
36
|
+
"dom_selector": { "type": "string" },
|
|
37
|
+
"computed_style_excerpt": { "type": "object" },
|
|
38
|
+
"evidence_hex_fg": { "type": "string" },
|
|
39
|
+
"evidence_hex_bg": { "type": "string" },
|
|
40
|
+
"evidence_contrast_ratio": { "type": "number" },
|
|
41
|
+
"evidence_px": { "type": "object" },
|
|
42
|
+
"suggested_fix": {
|
|
43
|
+
"type": "object",
|
|
44
|
+
"properties": {
|
|
45
|
+
"strategy": { "type": "string" },
|
|
46
|
+
"template_id": { "type": "string" },
|
|
47
|
+
"value_hint": { "type": "string" }
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"finding": { "type": "string" },
|
|
51
|
+
"first_seen_at": { "type": "string", "format": "date-time" },
|
|
52
|
+
"status": { "enum": ["new","persisted","resolved"] }
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
## {{session_date}} · `{{session_id}}` · branch `{{branch}}`
|
|
2
|
+
|
|
3
|
+
**Counts:** Applied {{applied}} · Proposed {{proposed}} · Skipped {{skipped}} · Failed {{failed}}
|
|
4
|
+
**Base:** `{{base_sha}}` · **Tip:** `{{tip_sha}}`
|
|
5
|
+
|
|
6
|
+
### Applied
|
|
7
|
+
| Finding | Category | Files | Commit |
|
|
8
|
+
|---|---|---|---|
|
|
9
|
+
{{applied_table}}
|
|
10
|
+
|
|
11
|
+
### Proposed (awaiting approval)
|
|
12
|
+
| Finding | Category | Files | Patch |
|
|
13
|
+
|---|---|---|---|
|
|
14
|
+
{{proposed_table}}
|
|
15
|
+
|
|
16
|
+
### Skipped (HIGH risk — tracked as issues)
|
|
17
|
+
| Finding | Issue | Reason |
|
|
18
|
+
|---|---|---|
|
|
19
|
+
{{skipped_table}}
|
|
20
|
+
|
|
21
|
+
### Failed (rolled back)
|
|
22
|
+
| Finding | Gate | Reason |
|
|
23
|
+
|---|---|---|
|
|
24
|
+
{{failed_table}}
|
|
25
|
+
|
|
26
|
+
---
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Design audit overview — {{project_name}}
|
|
2
|
+
|
|
3
|
+
> **{{mode_banner}}**
|
|
4
|
+
> {{changelog_body}}
|
|
5
|
+
|
|
6
|
+
## Executive summary
|
|
7
|
+
|
|
8
|
+
{{executive_summary}}
|
|
9
|
+
|
|
10
|
+
## Scorecard
|
|
11
|
+
|
|
12
|
+
| Category | Score | Blockers | High | Medium | Nitpicks |
|
|
13
|
+
|---|---|---|---|---|---|
|
|
14
|
+
| Nielsen heuristics | {{nielsen_score}}/40 | {{n_blockers_nielsen}} | {{n_high_nielsen}} | {{n_medium_nielsen}} | {{n_nits_nielsen}} |
|
|
15
|
+
| WCAG 2.2 AA | {{wcag_score}}% | {{n_blockers_wcag}} | {{n_high_wcag}} | {{n_medium_wcag}} | {{n_nits_wcag}} |
|
|
16
|
+
| Core Web Vitals | {{cwv_badge}} | {{n_blockers_cwv}} | {{n_high_cwv}} | — | — |
|
|
17
|
+
| Baymard (if applicable) | {{baymard_score}} | {{n_blockers_baymard}} | {{n_high_baymard}} | {{n_medium_baymard}} | — |
|
|
18
|
+
|
|
19
|
+
## Top findings
|
|
20
|
+
|
|
21
|
+
### 🚨 Blockers
|
|
22
|
+
{{blockers_table}}
|
|
23
|
+
|
|
24
|
+
### High priority
|
|
25
|
+
{{high_table}}
|
|
26
|
+
|
|
27
|
+
### Medium priority
|
|
28
|
+
{{medium_table}}
|
|
29
|
+
|
|
30
|
+
### Nitpicks
|
|
31
|
+
{{nitpicks_table}}
|
|
32
|
+
|
|
33
|
+
### ✅ Resolved since last audit
|
|
34
|
+
{{resolved_table}}
|
|
35
|
+
|
|
36
|
+
## Market positioning snapshot
|
|
37
|
+
{{market_snapshot}}
|
|
38
|
+
|
|
39
|
+
Full market analysis: `docs/super-design/market-analysis.md`.
|
|
40
|
+
|
|
41
|
+
## Remediation roadmap
|
|
42
|
+
{{roadmap_body}}
|
|
43
|
+
|
|
44
|
+
## Appendix — evidence
|
|
45
|
+
- Per-finding details: `docs/super-design/findings/F-*.md`
|
|
46
|
+
- Screenshots: `docs/super-design/.cache/screenshots/`
|
|
47
|
+
- axe-core outputs: `docs/super-design/.cache/axe/`
|
|
48
|
+
- Web Vitals: `docs/super-design/.cache/vitals/`
|
|
49
|
+
- Audit history: `docs/super-design/audit-history.md`
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
*Generated by super-design v{{version}} on {{timestamp}}. Session: `{{session_id}}`.*
|