skills-ws 1.3.2 → 1.4.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/CHANGELOG.md +39 -0
- package/README.md +10 -9
- package/REVIEW.md +516 -0
- package/SECURITY.md +45 -0
- package/app/cli/page.tsx +100 -0
- package/app/docs/page.tsx +117 -0
- package/app/faq/page.tsx +92 -0
- package/app/globals.css +25 -0
- package/app/layout.tsx +248 -0
- package/app/not-found.tsx +22 -0
- package/app/page.tsx +141 -0
- package/app/sitemap.ts +25 -0
- package/app/skills/[name]/page.tsx +192 -0
- package/components/AsciiBackground.tsx +207 -0
- package/components/FaqAccordion.tsx +45 -0
- package/components/InstallBox.tsx +43 -0
- package/components/NpmDownloads.tsx +43 -0
- package/components/SkillContent.tsx +103 -0
- package/components/SkillsGrid.tsx +132 -0
- package/lib/skills.ts +47 -0
- package/next-env.d.ts +5 -0
- package/next.config.mjs +7 -0
- package/npm-package.json +56 -0
- package/package.json +29 -18
- package/postcss.config.mjs +8 -0
- package/public/favicon.ico +0 -0
- package/public/favicon.svg +4 -0
- package/public/install.sh +111 -0
- package/public/llms-full.txt +1000 -0
- package/public/llms.txt +83 -0
- package/public/og.png +0 -0
- package/public/robots.txt +51 -0
- package/public/skills.json +2335 -0
- package/skills/ai-agent-building/SKILL.md +988 -0
- package/skills/{aleph-vm-replication → aleph-cloud-self-deployment}/SKILL.md +21 -20
- package/skills/api-design/SKILL.md +827 -145
- package/skills/aws-production-deploy/SKILL.md +951 -0
- package/skills/ci-cd-pipeline/SKILL.md +846 -0
- package/skills/content-strategy/SKILL.md +831 -57
- package/skills/copywriting/SKILL.md +859 -84
- package/skills/docker-production/SKILL.md +744 -0
- package/skills/email-sequence/SKILL.md +673 -55
- package/skills/monitoring-observability/SKILL.md +872 -0
- package/skills/nextjs-performance/SKILL.md +557 -0
- package/skills/page-cro/SKILL.md +730 -76
- package/skills/paid-ads/SKILL.md +632 -74
- package/skills/popup-cro/SKILL.md +892 -34
- package/skills/postgres-mastery/SKILL.md +765 -0
- package/skills/programmatic-seo/SKILL.md +888 -47
- package/skills/security-hardening/SKILL.md +754 -104
- package/skills/seo-geo/SKILL.md +549 -91
- package/skills/signup-flow-cro/SKILL.md +1357 -60
- package/skills/stripe-billing/SKILL.md +735 -0
- package/skills/ui-ux-pro-max/SKILL.md +1122 -50
- package/skills-data/ab-testing/SKILL.md +171 -0
- package/skills-data/accounting-finance/SKILL.md +139 -0
- package/skills-data/affiliate-marketing/SKILL.md +152 -0
- package/{skills → skills-data}/ai-agent-design/SKILL.md +2 -2
- package/skills-data/api-design/SKILL.md +226 -0
- package/skills-data/ascii-banner/SKILL.md +317 -0
- package/skills-data/bing-webmaster/SKILL.md +130 -0
- package/skills-data/blog-engine/SKILL.md +91 -0
- package/skills-data/brand-strategy/SKILL.md +205 -0
- package/skills-data/business-development/SKILL.md +140 -0
- package/skills-data/cicd-pipelines/SKILL.md +232 -0
- package/skills-data/cold-outreach/SKILL.md +169 -0
- package/skills-data/community-building/SKILL.md +144 -0
- package/skills-data/competitor-intelligence/SKILL.md +145 -0
- package/skills-data/content-strategy/SKILL.md +85 -0
- package/skills-data/copywriting/SKILL.md +88 -0
- package/skills-data/crm-builder/SKILL.md +86 -0
- package/skills-data/crm-operations/SKILL.md +148 -0
- package/skills-data/customer-acquisition/SKILL.md +133 -0
- package/skills-data/customer-feedback/SKILL.md +140 -0
- package/skills-data/data-analytics/SKILL.md +203 -0
- package/skills-data/data-management/SKILL.md +199 -0
- package/skills-data/database-design/SKILL.md +158 -0
- package/skills-data/email-sequence/SKILL.md +81 -0
- package/skills-data/eu-legal-compliance/SKILL.md +156 -0
- package/skills-data/git-workflow/SKILL.md +200 -0
- package/skills-data/google-analytics/SKILL.md +188 -0
- package/skills-data/growth-hacking/SKILL.md +75 -0
- package/skills-data/hiring-team-building/SKILL.md +172 -0
- package/skills-data/influencer-marketing/SKILL.md +181 -0
- package/skills-data/landing-page-builder/SKILL.md +93 -0
- package/skills-data/lead-scoring/SKILL.md +64 -0
- package/skills-data/local-seo/SKILL.md +70 -0
- package/skills-data/marketing-analytics/SKILL.md +106 -0
- package/skills-data/mvp-launcher/SKILL.md +145 -0
- package/skills-data/nextjs-stack/SKILL.md +231 -0
- package/skills-data/page-cro/SKILL.md +80 -0
- package/skills-data/paid-ads/SKILL.md +110 -0
- package/skills-data/popup-cro/SKILL.md +52 -0
- package/skills-data/pr-media-outreach/SKILL.md +140 -0
- package/skills-data/pricing-optimization/SKILL.md +316 -0
- package/skills-data/programmatic-seo/SKILL.md +65 -0
- package/skills-data/project-management/SKILL.md +161 -0
- package/skills-data/prompt-engineering/SKILL.md +189 -0
- package/skills-data/retention-analytics/SKILL.md +161 -0
- package/skills-data/revenue-operations/SKILL.md +162 -0
- package/skills-data/sales-funnel/SKILL.md +56 -0
- package/skills-data/search-console/SKILL.md +159 -0
- package/skills-data/security-hardening/SKILL.md +176 -0
- package/skills-data/seo-geo/SKILL.md +138 -0
- package/skills-data/signup-flow-cro/SKILL.md +64 -0
- package/skills-data/smart-contract-auditor/SKILL.md +64 -0
- package/skills-data/social-media-growth/SKILL.md +146 -0
- package/skills-data/social-media-kit/SKILL.md +56 -0
- package/skills-data/testing-strategy/SKILL.md +344 -0
- package/skills-data/ui-ux-pro-max/SKILL.md +72 -0
- package/skills-data/virustotal/SKILL.md +108 -0
- package/skills-data/web-performance/SKILL.md +219 -0
- package/skills-data/webinar-events/SKILL.md +148 -0
- package/skills-data/yandex-webmaster/SKILL.md +159 -0
- package/skills.json +2335 -0
- package/tailwind.config.ts +45 -0
- package/tsconfig.json +26 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [Unreleased] — 2026-02-28
|
|
4
|
+
|
|
5
|
+
### Added — Premium Skills Tier
|
|
6
|
+
|
|
7
|
+
**10 premium skills added:**
|
|
8
|
+
- `aws-production-deploy` — ECS, RDS, CloudFront, Route53, SSL, monitoring, CDK/Terraform
|
|
9
|
+
- `stripe-billing` — Subscriptions, usage-based billing, webhooks, customer portal, metering
|
|
10
|
+
- `security-hardening` — OWASP Top 10, CSP, rate limiting, auth, pentesting checklist
|
|
11
|
+
- `ai-agent-building` — CrewAI, LangGraph, tool use, memory systems, multi-agent orchestration
|
|
12
|
+
- `nextjs-performance` — Core Web Vitals, ISR/SSG, edge functions, bundle analysis
|
|
13
|
+
- `postgres-mastery` — Indexes, query optimization, partitioning, pgvector, migrations
|
|
14
|
+
- `docker-production` — Multi-stage builds, compose, secrets, health checks, security
|
|
15
|
+
- `api-design` — REST best practices, versioning, pagination, OpenAPI, rate limiting
|
|
16
|
+
- `monitoring-observability` — Prometheus, Grafana, Datadog, SLOs, OpenTelemetry
|
|
17
|
+
- `ci-cd-pipeline` — GitHub Actions, testing pyramid, deployment gates, feature flags
|
|
18
|
+
|
|
19
|
+
**UI changes:**
|
|
20
|
+
- Premium skills show 🔒 lock icon and amber "Premium" badge on skill cards
|
|
21
|
+
- Premium skill detail pages show 30-line preview with gradient fade, then paywall CTA
|
|
22
|
+
- CTA button: "Get all premium skills — $49/year" linking to `NEXT_PUBLIC_PREMIUM_URL` env var
|
|
23
|
+
- New "★ Premium" filter button in skill category bar
|
|
24
|
+
- Premium skill count shown in footer stats (amber colored)
|
|
25
|
+
- Free skills remain fully accessible — no changes
|
|
26
|
+
|
|
27
|
+
**Files changed:**
|
|
28
|
+
- `lib/skills.ts` — Added `premium?: boolean` to Skill interface
|
|
29
|
+
- `skills.json` + `public/skills.json` — 10 new skills with `"premium": true`
|
|
30
|
+
- `components/SkillsGrid.tsx` — Premium badge, lock icon, premium filter button
|
|
31
|
+
- `components/PremiumGate.tsx` — New component: preview + paywall CTA
|
|
32
|
+
- `app/skills/[name]/page.tsx` — Premium badge on detail page, PremiumGate for premium content
|
|
33
|
+
- `app/page.tsx` — Premium skills count in stats section
|
|
34
|
+
|
|
35
|
+
**Notes:**
|
|
36
|
+
- Total skills: 80 (70 free + 10 premium)
|
|
37
|
+
- Static export — paywall is client-side only (intentionally bypassable for v1)
|
|
38
|
+
- CLI package unchanged — premium skills are web-only
|
|
39
|
+
- Build passes: 86 static pages generated
|
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
#
|
|
1
|
+
# SKILLS.ws
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
77 expert agent skills for AI coding assistants.
|
|
4
4
|
|
|
5
|
-
**Website:** [
|
|
5
|
+
**Website:** [SKILLS.ws](https://skills.ws)
|
|
6
6
|
**npm:** [npmjs.com/package/skills-ws](https://www.npmjs.com/package/skills-ws)
|
|
7
7
|
|
|
8
8
|
## Install skills
|
|
@@ -20,13 +20,14 @@ Skills are `SKILL.md` files that give AI coding assistants specialized knowledge
|
|
|
20
20
|
|
|
21
21
|
## Categories
|
|
22
22
|
|
|
23
|
-
- **Marketing** — SEO/GEO, content strategy, copywriting, paid ads, email sequences, PR/media, influencer, brand strategy, webinars, blog engine
|
|
24
|
-
- **Dev** — Git workflow, CI/CD, API design, database design, testing, web performance, security hardening, prompt engineering, AI agent
|
|
25
|
-
- **Growth** — Social media, community building, customer feedback, business development, cold outreach, competitor intelligence, affiliate marketing
|
|
23
|
+
- **Marketing** — SEO/GEO, content strategy, copywriting, paid ads, email sequences, PR/media, influencer, brand strategy, webinars, blog engine, social media kit
|
|
24
|
+
- **Dev** — Git workflow, CI/CD, API design, database design, testing, web performance, security hardening, prompt engineering, AI agent building, MVP launcher, Next.js stack, Next.js performance, PostgreSQL, Docker, AWS deploy, monitoring, Stripe billing, auth
|
|
25
|
+
- **Growth** — Social media, community building, customer feedback, business development, cold outreach, competitor intelligence, affiliate marketing, growth hacking, product-led growth, marketplace launch
|
|
26
26
|
- **Conversion** — Landing pages, signup flows, popups, A/B testing, pricing optimization, lead scoring, CRO, sales funnels
|
|
27
|
-
- **Analytics** — Google Analytics, Search Console, Bing/Yandex Webmaster, data analytics, retention analytics
|
|
28
|
-
- **Operations** — EU legal compliance (GDPR, AI Act, DSA), hiring/team building, project management, CRM,
|
|
29
|
-
- **
|
|
27
|
+
- **Analytics** — Google Analytics, Search Console, Bing/Yandex Webmaster, data analytics, retention analytics, marketing analytics, on-chain analytics
|
|
28
|
+
- **Operations** — EU legal compliance (GDPR, AI Act, DSA), EU tax & accounting, hiring/team building, project management, CRM, revenue ops
|
|
29
|
+
- **Web3** — Solidity dev, DeFi integration, smart contract auditor, wallet integration, Aleph Cloud self-deployment
|
|
30
|
+
- **Design** — UI/UX Pro Max, landing page builder, design system, ASCII banner
|
|
30
31
|
|
|
31
32
|
## Development
|
|
32
33
|
|
package/REVIEW.md
ADDED
|
@@ -0,0 +1,516 @@
|
|
|
1
|
+
# Repository Review & Code Audit — skills.ws
|
|
2
|
+
|
|
3
|
+
**Date:** 2026-02-26
|
|
4
|
+
**Repo:** san-npm/skills-ws
|
|
5
|
+
**Branch:** claude/repo-review-audit-DLdT5
|
|
6
|
+
**Stack:** Next.js 14.2 (static export), React 18, TypeScript, Tailwind CSS, Three.js
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Project Overview
|
|
11
|
+
|
|
12
|
+
A Next.js website for **skills.ws** — a catalog of 60 agent skills (SKILL.md files) for AI coding assistants (OpenClaw, Claude Code, Cursor, Codex, Gemini CLI). The site serves as a marketing homepage, documentation hub, and installation gateway via `npx skills-ws`.
|
|
13
|
+
|
|
14
|
+
### Architecture
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
app/
|
|
18
|
+
layout.tsx — Root layout: nav, GA4, 4× JSON-LD schemas
|
|
19
|
+
page.tsx — Homepage: ASCII banner, search/filter grid, stats
|
|
20
|
+
sitemap.ts — Dynamic XML sitemap
|
|
21
|
+
not-found.tsx — Custom 404
|
|
22
|
+
skills/[name]/ — Dynamic skill detail pages (SSG)
|
|
23
|
+
docs/ — Static docs page
|
|
24
|
+
cli/ — CLI reference page
|
|
25
|
+
faq/ — FAQ with accordion + FAQPage schema
|
|
26
|
+
components/
|
|
27
|
+
AsciiBackground — WebGL Three.js → ASCII art canvas (homepage only)
|
|
28
|
+
SkillsGrid — Client-side search/filter grid
|
|
29
|
+
SkillContent — Markdown renderer (react-markdown + remark-gfm)
|
|
30
|
+
InstallBox — Copy-to-clipboard install command
|
|
31
|
+
FaqAccordion — Expandable Q&A
|
|
32
|
+
NpmDownloads — Live npm download counter (client-side, cached)
|
|
33
|
+
lib/
|
|
34
|
+
skills.ts — Skill data access, types, category colors
|
|
35
|
+
skills.json — 60 skills with full markdown content (~357KB)
|
|
36
|
+
skills-data/ — 60 directories, each with SKILL.md
|
|
37
|
+
public/
|
|
38
|
+
skills.json — Served copy (should match root)
|
|
39
|
+
install.sh — Bash installer script
|
|
40
|
+
llms.txt — LLM-readable skill index
|
|
41
|
+
llms-full.txt — Full LLM content dump
|
|
42
|
+
robots.txt — Crawl directives + sitemap
|
|
43
|
+
og.png — OpenGraph image (1200×630)
|
|
44
|
+
favicon.ico — Favicon (32×32)
|
|
45
|
+
favicon.svg — SVG favicon
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Findings Summary
|
|
51
|
+
|
|
52
|
+
| Severity | Count |
|
|
53
|
+
|----------|-------|
|
|
54
|
+
| CRITICAL | 2 |
|
|
55
|
+
| HIGH | 9 |
|
|
56
|
+
| MEDIUM | 16 |
|
|
57
|
+
| LOW | 14 |
|
|
58
|
+
| **Total** | **41** |
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## CRITICAL
|
|
63
|
+
|
|
64
|
+
### 1. Hardcoded "60" skill count in metadata will drift on every skill addition
|
|
65
|
+
|
|
66
|
+
**Files:** `app/layout.tsx:21,61,75,190` · `app/cli/page.tsx:7`
|
|
67
|
+
**Category:** SEO / Maintenance
|
|
68
|
+
|
|
69
|
+
The string `"60 agent skills"` is hardcoded in 5 places across meta description, OpenGraph, Twitter card, and SoftwareApplication JSON-LD. The homepage body correctly uses `{skills.length}` and the CLI page body uses `{skillCount}`, but all `<meta>` descriptions are static strings. Every skill addition requires a multi-file find-and-replace — a maintenance trap that guarantees stale SEO data.
|
|
70
|
+
|
|
71
|
+
**Fix:** Derive the count from `getSkills().length` in metadata generation, or remove specific numbers from static meta strings.
|
|
72
|
+
|
|
73
|
+
### 2. `install.sh` `--dir` flag has no input validation — path traversal
|
|
74
|
+
|
|
75
|
+
**File:** `public/install.sh:44-46`
|
|
76
|
+
**Category:** Security
|
|
77
|
+
|
|
78
|
+
The `--skill` flag correctly validates against `^[a-z0-9-]+$`, but the `--dir` flag accepts any arbitrary string with zero validation. An attacker could pass `--dir /etc/cron.d` or `--dir ../../etc` to write files to arbitrary directories.
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
--dir)
|
|
82
|
+
TARGET_DIR="$2" # no sanitization
|
|
83
|
+
shift 2
|
|
84
|
+
;;
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
**Fix:** Validate that the directory is a relative path, reject paths containing `..`, and ensure it resolves within the working directory.
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## HIGH
|
|
92
|
+
|
|
93
|
+
### 2. Dead `useNpmDownloads()` hook — 22 lines of unused client code
|
|
94
|
+
|
|
95
|
+
**File:** `components/SkillsGrid.tsx:8-29`
|
|
96
|
+
**Category:** Dead Code / Bundle Size
|
|
97
|
+
|
|
98
|
+
A complete custom hook `useNpmDownloads()` is defined (with `useState`, `useEffect`, `fetch`, `sessionStorage` caching) but never called anywhere. The identical logic already lives in `components/NpmDownloads.tsx` which is the component actually used. This is dead code that inflates the client bundle.
|
|
99
|
+
|
|
100
|
+
**Fix:** Delete lines 8-29 from `SkillsGrid.tsx`.
|
|
101
|
+
|
|
102
|
+
### 3. BreadcrumbList schema is static and incorrect on 60+ pages
|
|
103
|
+
|
|
104
|
+
**File:** `app/layout.tsx:205-240`
|
|
105
|
+
**Category:** SEO / Structured Data
|
|
106
|
+
|
|
107
|
+
The BreadcrumbList JSON-LD is injected in the root layout and always shows the same 4 items (Home → Skills → Docs → CLI). This renders on every page including `/faq`, all 60 `/skills/[name]` pages, and the 404. A BreadcrumbList should represent the navigational path to the *current* page. Google may show incorrect breadcrumbs in SERPs for skill pages.
|
|
108
|
+
|
|
109
|
+
**Fix:** Move breadcrumb generation to individual pages or generate dynamically based on route.
|
|
110
|
+
|
|
111
|
+
### 4. FaqAccordion has zero ARIA attributes — WCAG 4.1.2 failure
|
|
112
|
+
|
|
113
|
+
**File:** `components/FaqAccordion.tsx:17-34`
|
|
114
|
+
**Category:** Accessibility
|
|
115
|
+
|
|
116
|
+
The accordion buttons lack `aria-expanded`, `aria-controls`, and `id`. The panels lack `role="region"`, `aria-labelledby`, and `id`. Screen readers cannot determine which items are expanded or collapsed. This is a WCAG 2.1 Level A violation.
|
|
117
|
+
|
|
118
|
+
**Fix:** Add `aria-expanded={open === i}`, `aria-controls={`faq-panel-${i}`}` to buttons. Add `id`, `role="region"`, `aria-labelledby` to panels.
|
|
119
|
+
|
|
120
|
+
### 5. `<nav>` has no accessible label
|
|
121
|
+
|
|
122
|
+
**File:** `app/layout.tsx:111`
|
|
123
|
+
**Category:** Accessibility
|
|
124
|
+
|
|
125
|
+
The `<nav>` element has no `aria-label`. If a page has multiple nav landmarks, screen reader users cannot distinguish them.
|
|
126
|
+
|
|
127
|
+
**Fix:** Add `aria-label="Main navigation"`.
|
|
128
|
+
|
|
129
|
+
### 6. `softwareVersion` in JSON-LD conflicts with `skills.json` version
|
|
130
|
+
|
|
131
|
+
**File:** `app/layout.tsx:188`
|
|
132
|
+
**Category:** SEO / Structured Data
|
|
133
|
+
|
|
134
|
+
The SoftwareApplication schema says `softwareVersion: "0.1.0"` (matching `package.json`), but all 60 skills in `skills.json` say `"version": "1.0.0"`. These are different things (CLI version vs skill version), but the inconsistency could confuse search engines. No single source of truth.
|
|
135
|
+
|
|
136
|
+
**Fix:** Import version from `package.json` dynamically for the CLI version.
|
|
137
|
+
|
|
138
|
+
### 7. `.gitignore` is dangerously minimal — missing `.env*` patterns
|
|
139
|
+
|
|
140
|
+
**File:** `.gitignore`
|
|
141
|
+
**Category:** Security
|
|
142
|
+
|
|
143
|
+
The entire `.gitignore` is only 3 lines (`node_modules/`, `.next/`, `out/`). Critical missing entries:
|
|
144
|
+
|
|
145
|
+
| Missing pattern | Risk |
|
|
146
|
+
|----------------|------|
|
|
147
|
+
| `.env` / `.env.*` / `.env.local` | **Secrets could be committed accidentally** |
|
|
148
|
+
| `*.pem` / `*.key` | SSL/signing keys leaked |
|
|
149
|
+
| `.vercel` | Deployment cache with tokens |
|
|
150
|
+
| `.DS_Store` / `Thumbs.db` | OS artifacts |
|
|
151
|
+
| `coverage/` / `*.log` | Build artifacts |
|
|
152
|
+
|
|
153
|
+
While no `.env` files currently exist in the repo, any developer who creates one could accidentally commit secrets.
|
|
154
|
+
|
|
155
|
+
**Fix:** Add at minimum: `.env*`, `*.pem`, `*.key`, `.vercel`, `.DS_Store`.
|
|
156
|
+
|
|
157
|
+
### 8. `install.sh` unknown arguments silently ignored — typos cause full install
|
|
158
|
+
|
|
159
|
+
**File:** `public/install.sh:48-50`
|
|
160
|
+
**Category:** UX / Safety
|
|
161
|
+
|
|
162
|
+
The wildcard case `*)` silently discards any unknown flag. If a user typos `--skiil seo-geo`, the flag is consumed and the script installs ALL 60 skills instead of the intended one.
|
|
163
|
+
|
|
164
|
+
**Fix:** Print an error and exit on unrecognized arguments.
|
|
165
|
+
|
|
166
|
+
### 9. `install.sh` missing argument guard on `--skill`/`--dir`
|
|
167
|
+
|
|
168
|
+
**File:** `public/install.sh:40-47`
|
|
169
|
+
**Category:** Robustness
|
|
170
|
+
|
|
171
|
+
If a user runs `bash install.sh --skill` (without a value), `$2` is unset. Under `set -u`, this produces a cryptic "unbound variable" error instead of a helpful message.
|
|
172
|
+
|
|
173
|
+
**Fix:** Check `$# -ge 2` before accessing `$2`.
|
|
174
|
+
|
|
175
|
+
### 10. 18 skills have content drift between SKILL.md and skills.json
|
|
176
|
+
|
|
177
|
+
**Files:** 18 skill directories in `skills-data/`
|
|
178
|
+
**Category:** Data Integrity
|
|
179
|
+
|
|
180
|
+
18 of 60 skills have SKILL.md bodies that differ from their `content` field in `skills.json`. The pattern is consistent: SKILL.md files contain markdown hyperlinks (e.g., `[references/technical-seo.md](references/technical-seo.md)`) while `skills.json` has plain text references.
|
|
181
|
+
|
|
182
|
+
**Affected skills:** seo-geo, content-strategy, copywriting, page-cro, email-sequence, paid-ads, signup-flow-cro, popup-cro, programmatic-seo, growth-hacking, landing-page-builder, lead-scoring, local-seo, marketing-analytics, crm-builder, sales-funnel, smart-contract-auditor, social-media-kit.
|
|
183
|
+
|
|
184
|
+
**Fix:** Decide on a single source of truth (SKILL.md or skills.json) and create a build step to keep them in sync.
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## MEDIUM
|
|
189
|
+
|
|
190
|
+
### 11. No `<main>` landmark wrapping page content
|
|
191
|
+
|
|
192
|
+
**File:** `app/layout.tsx:132`
|
|
193
|
+
**Category:** Accessibility
|
|
194
|
+
|
|
195
|
+
`{children}` is wrapped in `<div className="relative z-10">` instead of `<main>`. Screen readers use the `<main>` landmark to skip navigation (WCAG 2.4.1).
|
|
196
|
+
|
|
197
|
+
**Fix:** Change `<div>` to `<main>`.
|
|
198
|
+
|
|
199
|
+
### 12. Search input has no label
|
|
200
|
+
|
|
201
|
+
**File:** `components/SkillsGrid.tsx:68-76`
|
|
202
|
+
**Category:** Accessibility
|
|
203
|
+
|
|
204
|
+
The search `<input>` has a placeholder but no `<label>`, `aria-label`, or `aria-labelledby`. Placeholder is not a substitute for a label (WCAG 1.3.1, 3.3.2).
|
|
205
|
+
|
|
206
|
+
**Fix:** Add `aria-label="Search skills"`.
|
|
207
|
+
|
|
208
|
+
### 13. Category filter buttons lack `aria-pressed` state
|
|
209
|
+
|
|
210
|
+
**File:** `components/SkillsGrid.tsx:80-102`
|
|
211
|
+
**Category:** Accessibility
|
|
212
|
+
|
|
213
|
+
Filter buttons change visual style when selected but have no `aria-pressed` or `aria-current` to communicate active state to assistive technology.
|
|
214
|
+
|
|
215
|
+
**Fix:** Add `aria-pressed={filter === cat}` to each button.
|
|
216
|
+
|
|
217
|
+
### 14. Collapsed accordion content is in the accessibility tree
|
|
218
|
+
|
|
219
|
+
**File:** `components/FaqAccordion.tsx:26-28`
|
|
220
|
+
**Category:** Accessibility
|
|
221
|
+
|
|
222
|
+
Hidden content uses `maxHeight: "0px"` with `overflow: hidden`, but remains in the accessibility tree. Screen readers will read collapsed answers.
|
|
223
|
+
|
|
224
|
+
**Fix:** Add `aria-hidden={open !== i}` to collapsed panels.
|
|
225
|
+
|
|
226
|
+
### 15. Markdown `h1` creates duplicate `<h1>` on skill pages
|
|
227
|
+
|
|
228
|
+
**File:** `components/SkillContent.tsx:13`
|
|
229
|
+
**Category:** SEO
|
|
230
|
+
|
|
231
|
+
The markdown renderer maps `h1` to `<h1>`. Skill pages already have an `<h1>` for the skill name (`app/skills/[name]/page.tsx:122`). When skill content starts with `# Title`, the page has two `<h1>` elements — an SEO violation.
|
|
232
|
+
|
|
233
|
+
**Fix:** Map markdown `h1` → `<h2>`, `h2` → `<h3>`, etc. in the SkillContent component.
|
|
234
|
+
|
|
235
|
+
### 16. GA4 uses `dangerouslySetInnerHTML` instead of Next.js `<Script>`
|
|
236
|
+
|
|
237
|
+
**File:** `app/layout.tsx:103-108`
|
|
238
|
+
**Category:** Performance
|
|
239
|
+
|
|
240
|
+
The GA4 snippet is a render-blocking `<script>` in `<head>`. Next.js provides `<Script strategy="afterInteractive">` which defers loading for better performance and CSP compatibility.
|
|
241
|
+
|
|
242
|
+
**Fix:** Replace with `import Script from 'next/script'` and use `<Script strategy="afterInteractive">`.
|
|
243
|
+
|
|
244
|
+
### 17. `NpmDownloads` returns `null` during loading — CLS issue
|
|
245
|
+
|
|
246
|
+
**File:** `components/NpmDownloads.tsx:27`
|
|
247
|
+
**Category:** UX / Performance
|
|
248
|
+
|
|
249
|
+
When `downloads` is `null` (before fetch completes), the component returns `null`. The parent stat block still renders the "npm downloads" label with an empty number area, causing Cumulative Layout Shift.
|
|
250
|
+
|
|
251
|
+
**Fix:** Return a placeholder (e.g., `"—"` or a skeleton) instead of `null`.
|
|
252
|
+
|
|
253
|
+
### 18. `setTimeout` not cancelled on unmount in InstallBox
|
|
254
|
+
|
|
255
|
+
**File:** `components/InstallBox.tsx:11-12`
|
|
256
|
+
**Category:** React Anti-pattern
|
|
257
|
+
|
|
258
|
+
`setTimeout(() => setCopied(false), 1500)` is not cleaned up on unmount. Multiple rapid clicks also accumulate timers.
|
|
259
|
+
|
|
260
|
+
**Fix:** Store timeout in a `useRef`, clear on unmount and on subsequent clicks.
|
|
261
|
+
|
|
262
|
+
### 19. Fetch calls don't check `response.ok` before `.json()`
|
|
263
|
+
|
|
264
|
+
**Files:** `components/NpmDownloads.tsx:16` · `components/SkillsGrid.tsx:18`
|
|
265
|
+
**Category:** Error Handling
|
|
266
|
+
|
|
267
|
+
Both fetch calls chain `.then(r => r.json())` without checking `r.ok`. Errors are silently swallowed by `.catch(() => {})`. No logging, no retry, no user feedback.
|
|
268
|
+
|
|
269
|
+
**Fix:** Add `if (!r.ok) throw new Error(r.statusText)` before `.json()`. Add at least `console.warn` in catch.
|
|
270
|
+
|
|
271
|
+
### 20. Non-null assertions on canvas contexts
|
|
272
|
+
|
|
273
|
+
**File:** `components/AsciiBackground.tsx:36,42`
|
|
274
|
+
**Category:** Robustness
|
|
275
|
+
|
|
276
|
+
`getContext("2d")!` uses non-null assertions. While rare, `getContext` can return `null` in constrained environments (too many canvas contexts). Would cause unhandled TypeError.
|
|
277
|
+
|
|
278
|
+
**Fix:** Add null checks with early return, similar to the WebGL try/catch on line 24.
|
|
279
|
+
|
|
280
|
+
### 21. Accordion max-height of 500px clips long answers on mobile
|
|
281
|
+
|
|
282
|
+
**File:** `components/FaqAccordion.tsx:28`
|
|
283
|
+
**Category:** UX
|
|
284
|
+
|
|
285
|
+
`maxHeight: "500px"` hard-caps expanded panel height. On narrow mobile screens, long FAQ answers will be clipped with no scroll.
|
|
286
|
+
|
|
287
|
+
**Fix:** Use CSS `grid-template-rows: 0fr/1fr` transitions, or measure content height with a ref.
|
|
288
|
+
|
|
289
|
+
### 22. `react-markdown` v10 `li` component API may not pass `ordered`/`index` props
|
|
290
|
+
|
|
291
|
+
**File:** `components/SkillContent.tsx:27`
|
|
292
|
+
**Category:** Compatibility
|
|
293
|
+
|
|
294
|
+
The `li` component destructures `{ ordered, index }` props. In `react-markdown@^10.1.0`, these props may not be passed the same way as in v8/v9. If `ordered` is always `undefined`, ordered lists render with bullet style.
|
|
295
|
+
|
|
296
|
+
**Fix:** Verify against `react-markdown@10` docs and test ordered list rendering.
|
|
297
|
+
|
|
298
|
+
### 23. AsciiBackground decorative canvas not hidden from screen readers
|
|
299
|
+
|
|
300
|
+
**File:** `components/AsciiBackground.tsx:197-203`
|
|
301
|
+
**Category:** Accessibility
|
|
302
|
+
|
|
303
|
+
The ASCII canvas is purely decorative but lacks `aria-hidden="true"` or `role="presentation"`. Screen readers may announce it.
|
|
304
|
+
|
|
305
|
+
**Fix:** Add `aria-hidden="true"` and `role="presentation"` to the outer `<div>`.
|
|
306
|
+
|
|
307
|
+
### 24. Entire `skills.json` (357KB) bundled into homepage HTML
|
|
308
|
+
|
|
309
|
+
**File:** `lib/skills.ts` → `app/page.tsx`
|
|
310
|
+
**Category:** Performance
|
|
311
|
+
|
|
312
|
+
`lib/skills.ts` imports the full `skills.json` at module scope. Since Next.js static export serializes all data into the page HTML, the full markdown `content` fields for all 60 skills are embedded in `index.html` even though the homepage never renders skill content.
|
|
313
|
+
|
|
314
|
+
**Fix:** Split data — keep a lightweight index for the homepage, load full content only on skill detail pages.
|
|
315
|
+
|
|
316
|
+
---
|
|
317
|
+
|
|
318
|
+
## LOW
|
|
319
|
+
|
|
320
|
+
### 25. `install.sh` silent failure when no JSON parser available
|
|
321
|
+
|
|
322
|
+
**File:** `public/install.sh:59-71`
|
|
323
|
+
**Category:** UX
|
|
324
|
+
|
|
325
|
+
If neither `python3` nor `node` is installed, `$SKILLS` is empty and the `for skill in $SKILLS` loop silently does nothing. The script prints "Done. Installed 0 skills" with no explanation.
|
|
326
|
+
|
|
327
|
+
**Fix:** Check that `$SKILLS` is non-empty after parsing; print an error if both parsers are missing.
|
|
328
|
+
|
|
329
|
+
### 26. `SECURITY.md` references wrong directory
|
|
330
|
+
|
|
331
|
+
**File:** `SECURITY.md:41`
|
|
332
|
+
**Category:** Documentation
|
|
333
|
+
|
|
334
|
+
States "Skill content in `skills/` directory" but the actual path is `skills-data/`.
|
|
335
|
+
|
|
336
|
+
**Fix:** Change `skills/` to `skills-data/`.
|
|
337
|
+
|
|
338
|
+
---
|
|
339
|
+
|
|
340
|
+
## LOW
|
|
341
|
+
|
|
342
|
+
### 27. No `<h1>` on homepage
|
|
343
|
+
|
|
344
|
+
**File:** `app/page.tsx`
|
|
345
|
+
**Category:** SEO
|
|
346
|
+
|
|
347
|
+
The homepage has no `<h1>`. The ASCII `<pre>` is the visual title, but the first semantic heading is `<h2>` ("Security"). Every page should have exactly one `<h1>`.
|
|
348
|
+
|
|
349
|
+
**Fix:** Add a visually-hidden `<h1>` or make the subtitle an `<h1>`.
|
|
350
|
+
|
|
351
|
+
### 28. ASCII art `<pre>` is read character-by-character by screen readers
|
|
352
|
+
|
|
353
|
+
**File:** `app/page.tsx:27-29`
|
|
354
|
+
**Category:** Accessibility
|
|
355
|
+
|
|
356
|
+
The ASCII banner has no `aria-hidden="true"`. Screen readers announce hundreds of box-drawing characters.
|
|
357
|
+
|
|
358
|
+
**Fix:** Add `aria-hidden="true"` to the `<pre>`.
|
|
359
|
+
|
|
360
|
+
### 29. Sitemap `lastModified` is always current build time
|
|
361
|
+
|
|
362
|
+
**File:** `app/sitemap.ts:8`
|
|
363
|
+
**Category:** SEO
|
|
364
|
+
|
|
365
|
+
Every sitemap entry uses `new Date().toISOString()`. This defeats the purpose of `lastModified` — search engines may distrust timestamps or re-crawl unnecessarily.
|
|
366
|
+
|
|
367
|
+
**Fix:** Use git commit dates or static dates for pages that haven't changed.
|
|
368
|
+
|
|
369
|
+
### 30. Hardcoded hex colors in FAQ `<Code>` component bypass theme
|
|
370
|
+
|
|
371
|
+
**File:** `app/faq/page.tsx:12`
|
|
372
|
+
**Category:** Code Quality
|
|
373
|
+
|
|
374
|
+
The `Code` component uses `bg-[#0a0a0a]`, `border-[#222]`, `text-[#00ff88]` instead of theme tokens (`bg-bg`, `border-border`, `text-accent`).
|
|
375
|
+
|
|
376
|
+
**Fix:** Use Tailwind theme classes for consistency.
|
|
377
|
+
|
|
378
|
+
### 31. `"/"` keyboard shortcut doesn't guard all editable contexts
|
|
379
|
+
|
|
380
|
+
**File:** `components/SkillsGrid.tsx:42-53`
|
|
381
|
+
**Category:** UX
|
|
382
|
+
|
|
383
|
+
The global `"/"` shortcut only excludes `HTMLInputElement`. It doesn't check for `HTMLTextAreaElement`, `[contenteditable]`, or modifier keys.
|
|
384
|
+
|
|
385
|
+
**Fix:** Expand guard to include `HTMLTextAreaElement`, `HTMLSelectElement`, and `[contenteditable]`.
|
|
386
|
+
|
|
387
|
+
### 32. FAQ items keyed by array index
|
|
388
|
+
|
|
389
|
+
**File:** `components/FaqAccordion.tsx:16`
|
|
390
|
+
**Category:** React
|
|
391
|
+
|
|
392
|
+
`key={i}` uses index. Since the FAQ tracks open state by index (`open === i`), reordering the array would show the wrong FAQ as expanded.
|
|
393
|
+
|
|
394
|
+
**Fix:** Use `key={faq.q}` for a stable key.
|
|
395
|
+
|
|
396
|
+
### 33. `prefersReducedMotion` is checked once and not reactive
|
|
397
|
+
|
|
398
|
+
**File:** `components/AsciiBackground.tsx:17`
|
|
399
|
+
**Category:** UX
|
|
400
|
+
|
|
401
|
+
`matchMedia("(prefers-reduced-motion: reduce)").matches` is read once. If the user changes their system preference while the page is open, the animation won't respond.
|
|
402
|
+
|
|
403
|
+
**Fix:** Listen to `MediaQueryList.addEventListener("change", ...)`.
|
|
404
|
+
|
|
405
|
+
### 34. Decorative dots throughout UI lack `aria-hidden`
|
|
406
|
+
|
|
407
|
+
**Files:** `app/page.tsx:41,60-73` · `components/SkillsGrid.tsx:132` · `app/docs/page.tsx:55-110`
|
|
408
|
+
**Category:** Accessibility
|
|
409
|
+
|
|
410
|
+
Colored dot `<span>` elements are decorative but not excluded from the accessibility tree.
|
|
411
|
+
|
|
412
|
+
**Fix:** Add `aria-hidden="true"` to dot spans.
|
|
413
|
+
|
|
414
|
+
### 35. Category buttons lack per-category counts
|
|
415
|
+
|
|
416
|
+
**File:** `components/SkillsGrid.tsx:90-102`
|
|
417
|
+
**Category:** UX
|
|
418
|
+
|
|
419
|
+
The "All" button shows `All ({skills.length})` but individual category buttons show only the name with no count.
|
|
420
|
+
|
|
421
|
+
### 36. ESLint suppression without explanation
|
|
422
|
+
|
|
423
|
+
**File:** `components/AsciiBackground.tsx:194`
|
|
424
|
+
**Category:** Code Quality
|
|
425
|
+
|
|
426
|
+
`// eslint-disable-next-line react-hooks/exhaustive-deps` suppresses the rule. The empty dependency array is intentional but the suppression should explain why.
|
|
427
|
+
|
|
428
|
+
### 37. Checkbox `<input>` rendered as `<span>` in SkillContent
|
|
429
|
+
|
|
430
|
+
**File:** `components/SkillContent.tsx:89-93`
|
|
431
|
+
**Category:** Accessibility
|
|
432
|
+
|
|
433
|
+
Custom `input` renderer replaces actual checkboxes with a decorative `<span>`. No semantic role, no keyboard interactivity.
|
|
434
|
+
|
|
435
|
+
**Fix:** Use `role="checkbox"` and `aria-checked` on the span.
|
|
436
|
+
|
|
437
|
+
### 38. `llms-full.txt` sourced from `skills.json` — misses SKILL.md link updates
|
|
438
|
+
|
|
439
|
+
**File:** `public/llms-full.txt`
|
|
440
|
+
**Category:** Data Integrity
|
|
441
|
+
|
|
442
|
+
`llms-full.txt` matches `skills.json` content fields exactly, which means the 18 skills with updated markdown links in their SKILL.md files have those links absent from `llms-full.txt`. Low priority since the content is equivalent — just without hyperlinks.
|
|
443
|
+
|
|
444
|
+
### 39. `install.sh` `rmdir` fails silently on partially-written directories
|
|
445
|
+
|
|
446
|
+
**File:** `public/install.sh:95`
|
|
447
|
+
**Category:** Cleanup
|
|
448
|
+
|
|
449
|
+
If `curl` partially writes `SKILL.md` before failing, `rmdir "$SKILL_DIR"` fails because the directory is not empty. The `|| true` suppresses this, leaving orphan directories with incomplete files.
|
|
450
|
+
|
|
451
|
+
**Fix:** Use `rm -rf "$SKILL_DIR"` for cleanup on failure.
|
|
452
|
+
|
|
453
|
+
### 40. No `test` or `format` script in package.json
|
|
454
|
+
|
|
455
|
+
**File:** `package.json`
|
|
456
|
+
**Category:** Code Quality
|
|
457
|
+
|
|
458
|
+
No `"test"` script is defined — `npm test` fails. No Prettier or formatting tooling for consistent code style.
|
|
459
|
+
|
|
460
|
+
### 41. Next.js 14.2.35 is on a maintenance branch
|
|
461
|
+
|
|
462
|
+
**File:** `package.json`
|
|
463
|
+
**Category:** Dependencies
|
|
464
|
+
|
|
465
|
+
Next.js 14.2.x is a maintenance branch. Next.js 15 has been stable since late 2024 with Turbopack, React 19, and improved caching. The 14.2.x line has had multiple security advisories (SSRF, header injection). Not urgent for a static export site, but worth tracking.
|
|
466
|
+
|
|
467
|
+
---
|
|
468
|
+
|
|
469
|
+
## Data Integrity Summary
|
|
470
|
+
|
|
471
|
+
| Check | Status |
|
|
472
|
+
|-------|--------|
|
|
473
|
+
| skills-data directories | 60 |
|
|
474
|
+
| skills.json entries | 60 |
|
|
475
|
+
| llms.txt skills listed | 60 |
|
|
476
|
+
| llms-full.txt skills | 60 |
|
|
477
|
+
| public/skills.json entries | 60 |
|
|
478
|
+
| Directory ↔ skills.json match | 60/60 (all match) |
|
|
479
|
+
| SKILL.md ↔ skills.json content | 42/60 exact, 18 have link drift |
|
|
480
|
+
| robots.txt domain | skills.ws (correct) |
|
|
481
|
+
| Sitemap domain | skills.ws (correct) |
|
|
482
|
+
| install.sh domain | skills.ws (correct) |
|
|
483
|
+
| install.sh `--skill` validation | Present (regex `^[a-z0-9-]+$`) |
|
|
484
|
+
| install.sh `--dir` validation | **Missing** — path traversal possible |
|
|
485
|
+
|
|
486
|
+
### Category Distribution
|
|
487
|
+
|
|
488
|
+
| Category | Count |
|
|
489
|
+
|----------|-------|
|
|
490
|
+
| marketing | 15 |
|
|
491
|
+
| dev | 12 |
|
|
492
|
+
| conversion | 8 |
|
|
493
|
+
| growth | 8 |
|
|
494
|
+
| analytics | 7 |
|
|
495
|
+
| operations | 6 |
|
|
496
|
+
| design | 3 |
|
|
497
|
+
| web3 | 1 |
|
|
498
|
+
|
|
499
|
+
---
|
|
500
|
+
|
|
501
|
+
## Previously Fixed (this branch)
|
|
502
|
+
|
|
503
|
+
These issues from the prior audit (2026-02-23) have been resolved:
|
|
504
|
+
|
|
505
|
+
| Issue | Status |
|
|
506
|
+
|-------|--------|
|
|
507
|
+
| Stale `public/skills.json` (37 vs 60 skills) | Fixed — synced |
|
|
508
|
+
| FAQ schema JSX fallback to question text | Fixed — added `schemaA` field |
|
|
509
|
+
| `robots.txt` pointing to vercel subdomain | Fixed — `skills.ws` |
|
|
510
|
+
| FAQ page listing only 4 of 8 categories | Fixed — all 8 listed |
|
|
511
|
+
| Empty verification meta tags | Fixed — removed |
|
|
512
|
+
| `install.sh` path traversal via `--skill` | Fixed — regex validation |
|
|
513
|
+
| `install.sh` stale URLs | Fixed — `skills.ws` |
|
|
514
|
+
| `softwareVersion` mismatch with package.json | Fixed — `0.1.0` |
|
|
515
|
+
| AsciiBackground `ready` in useEffect deps | Fixed — removed |
|
|
516
|
+
| Missing `og.png` | Fixed — asset added |
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Supported Versions
|
|
4
|
+
|
|
5
|
+
| Version | Supported |
|
|
6
|
+
|---------|-----------|
|
|
7
|
+
| 1.x | ✅ Current |
|
|
8
|
+
| < 1.0 | ❌ No longer supported |
|
|
9
|
+
|
|
10
|
+
## Reporting a Vulnerability
|
|
11
|
+
|
|
12
|
+
If you discover a security vulnerability in skills-ws, please report it responsibly:
|
|
13
|
+
|
|
14
|
+
**Email:** bob@openletz.com
|
|
15
|
+
**Subject:** `[SECURITY] skills-ws: <brief description>`
|
|
16
|
+
|
|
17
|
+
Please include:
|
|
18
|
+
- Description of the vulnerability
|
|
19
|
+
- Steps to reproduce
|
|
20
|
+
- Potential impact
|
|
21
|
+
- Suggested fix (if any)
|
|
22
|
+
|
|
23
|
+
We will acknowledge receipt within 48 hours and provide a timeline for a fix.
|
|
24
|
+
|
|
25
|
+
**Do NOT open a public GitHub issue for security vulnerabilities.**
|
|
26
|
+
|
|
27
|
+
## Security Model
|
|
28
|
+
|
|
29
|
+
- **Zero runtime dependencies** — no supply chain risk from third-party packages
|
|
30
|
+
- **No code execution** — skills are markdown files (SKILL.md), not executable code
|
|
31
|
+
- **No eval/exec patterns** — the CLI copies files only, never evaluates content
|
|
32
|
+
- **Environment-only credentials** — skills that reference API keys use environment variables exclusively
|
|
33
|
+
- **VirusTotal scanned** — all skill files are periodically scanned
|
|
34
|
+
- **Build provenance** — npm packages are published with Sigstore provenance attestation
|
|
35
|
+
|
|
36
|
+
## Scope
|
|
37
|
+
|
|
38
|
+
This policy covers:
|
|
39
|
+
- The `skills-ws` npm package
|
|
40
|
+
- The CLI tool (`npx skills-ws`)
|
|
41
|
+
- Skill content in `skills-data/` directory
|
|
42
|
+
|
|
43
|
+
This policy does NOT cover:
|
|
44
|
+
- Third-party tools referenced in skill documentation (e.g., Google Analytics, VirusTotal)
|
|
45
|
+
- User-modified skill files after installation
|