skills-ws 1.5.0 → 1.5.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/LICENSE +21 -0
- package/README.md +5 -5
- package/bin/cli.mjs +93 -115
- package/package.json +18 -29
- package/CHANGELOG.md +0 -39
- package/REVIEW.md +0 -516
- package/app/cli/page.tsx +0 -100
- package/app/docs/page.tsx +0 -117
- package/app/faq/page.tsx +0 -92
- package/app/globals.css +0 -25
- package/app/layout.tsx +0 -248
- package/app/not-found.tsx +0 -22
- package/app/page.tsx +0 -141
- package/app/sitemap.ts +0 -25
- package/app/skills/[name]/page.tsx +0 -192
- package/components/AsciiBackground.tsx +0 -207
- package/components/FaqAccordion.tsx +0 -46
- package/components/InstallBox.tsx +0 -43
- package/components/NpmDownloads.tsx +0 -43
- package/components/SkillContent.tsx +0 -99
- package/components/SkillsGrid.tsx +0 -132
- package/lib/skills.ts +0 -47
- package/next-env.d.ts +0 -5
- package/next.config.mjs +0 -7
- package/npm-package.json +0 -56
- package/postcss.config.mjs +0 -8
- package/public/favicon.ico +0 -0
- package/public/favicon.svg +0 -4
- package/public/install.sh +0 -111
- package/public/llms-full.txt +0 -1000
- package/public/llms.txt +0 -83
- package/public/og.png +0 -0
- package/public/robots.txt +0 -51
- package/public/skills.json +0 -2444
- package/skills-data/ab-testing/SKILL.md +0 -171
- package/skills-data/accounting-finance/SKILL.md +0 -139
- package/skills-data/affiliate-marketing/SKILL.md +0 -152
- package/skills-data/ai-agent-design/SKILL.md +0 -207
- package/skills-data/api-design/SKILL.md +0 -226
- package/skills-data/ascii-banner/SKILL.md +0 -317
- package/skills-data/bing-webmaster/SKILL.md +0 -130
- package/skills-data/blog-engine/SKILL.md +0 -91
- package/skills-data/brand-strategy/SKILL.md +0 -205
- package/skills-data/business-development/SKILL.md +0 -140
- package/skills-data/cicd-pipelines/SKILL.md +0 -232
- package/skills-data/cold-outreach/SKILL.md +0 -169
- package/skills-data/community-building/SKILL.md +0 -144
- package/skills-data/competitor-intelligence/SKILL.md +0 -145
- package/skills-data/content-strategy/SKILL.md +0 -85
- package/skills-data/copywriting/SKILL.md +0 -88
- package/skills-data/crm-builder/SKILL.md +0 -86
- package/skills-data/crm-operations/SKILL.md +0 -148
- package/skills-data/customer-acquisition/SKILL.md +0 -133
- package/skills-data/customer-feedback/SKILL.md +0 -140
- package/skills-data/data-analytics/SKILL.md +0 -203
- package/skills-data/data-management/SKILL.md +0 -199
- package/skills-data/database-design/SKILL.md +0 -158
- package/skills-data/email-sequence/SKILL.md +0 -81
- package/skills-data/eu-legal-compliance/SKILL.md +0 -156
- package/skills-data/git-workflow/SKILL.md +0 -200
- package/skills-data/google-analytics/SKILL.md +0 -188
- package/skills-data/growth-hacking/SKILL.md +0 -75
- package/skills-data/hiring-team-building/SKILL.md +0 -172
- package/skills-data/influencer-marketing/SKILL.md +0 -181
- package/skills-data/landing-page-builder/SKILL.md +0 -93
- package/skills-data/lead-scoring/SKILL.md +0 -64
- package/skills-data/local-seo/SKILL.md +0 -70
- package/skills-data/marketing-analytics/SKILL.md +0 -106
- package/skills-data/mvp-launcher/SKILL.md +0 -145
- package/skills-data/nextjs-stack/SKILL.md +0 -231
- package/skills-data/page-cro/SKILL.md +0 -80
- package/skills-data/paid-ads/SKILL.md +0 -110
- package/skills-data/popup-cro/SKILL.md +0 -52
- package/skills-data/pr-media-outreach/SKILL.md +0 -140
- package/skills-data/pricing-optimization/SKILL.md +0 -316
- package/skills-data/programmatic-seo/SKILL.md +0 -65
- package/skills-data/project-management/SKILL.md +0 -161
- package/skills-data/prompt-engineering/SKILL.md +0 -189
- package/skills-data/retention-analytics/SKILL.md +0 -161
- package/skills-data/revenue-operations/SKILL.md +0 -162
- package/skills-data/sales-funnel/SKILL.md +0 -56
- package/skills-data/search-console/SKILL.md +0 -159
- package/skills-data/security-hardening/SKILL.md +0 -176
- package/skills-data/seo-geo/SKILL.md +0 -138
- package/skills-data/signup-flow-cro/SKILL.md +0 -64
- package/skills-data/smart-contract-auditor/SKILL.md +0 -64
- package/skills-data/social-media-growth/SKILL.md +0 -146
- package/skills-data/social-media-kit/SKILL.md +0 -56
- package/skills-data/testing-strategy/SKILL.md +0 -344
- package/skills-data/ui-ux-pro-max/SKILL.md +0 -72
- package/skills-data/virustotal/SKILL.md +0 -108
- package/skills-data/web-performance/SKILL.md +0 -219
- package/skills-data/webinar-events/SKILL.md +0 -148
- package/skills-data/yandex-webmaster/SKILL.md +0 -159
- package/skills.json +0 -2444
- package/tailwind.config.ts +0 -45
- package/tsconfig.json +0 -26
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Commit Media SARL
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# skills.ws
|
|
2
2
|
|
|
3
|
-
Agent skills for AI coding assistants.
|
|
3
|
+
Agent skills for AI coding assistants. 81 skills across 8 categories — built for OpenClaw, Claude Code, Cursor, Codex, and any agent that supports the SKILL.md format.
|
|
4
4
|
|
|
5
5
|
**Website:** [skills.ws](https://skills.ws) | **npm:** [skills-ws](https://www.npmjs.com/package/skills-ws) | **Docs:** [llms-full.txt](https://skills.ws/llms-full.txt)
|
|
6
6
|
|
|
@@ -19,7 +19,7 @@ Skills are `SKILL.md` files that give AI coding assistants specialized knowledge
|
|
|
19
19
|
|
|
20
20
|
---
|
|
21
21
|
|
|
22
|
-
## Skills (
|
|
22
|
+
## Skills (81 across 8 categories)
|
|
23
23
|
|
|
24
24
|
### Marketing (15)
|
|
25
25
|
SEO/GEO, content strategy, copywriting, paid ads, email sequences, PR/media, influencer marketing, brand strategy, webinars, blog engine, and more.
|
|
@@ -156,9 +156,9 @@ skills-ws/
|
|
|
156
156
|
│ └── NpmDownloads.tsx # Live npm download counter
|
|
157
157
|
├── lib/
|
|
158
158
|
│ └── skills.ts # Skill data access + TypeScript interfaces
|
|
159
|
-
├── skills/ # Raw SKILL.md files (
|
|
159
|
+
├── skills/ # Raw SKILL.md files (81 directories)
|
|
160
160
|
├── public/
|
|
161
|
-
│ ├── skills.json # Skills database (
|
|
161
|
+
│ ├── skills.json # Skills database (81 skills, all metadata + content)
|
|
162
162
|
│ ├── llms.txt # LLM-readable skill index
|
|
163
163
|
│ ├── llms-full.txt # Full content dump for LLMs
|
|
164
164
|
│ ├── robots.txt # Crawl directives
|
|
@@ -170,7 +170,7 @@ skills-ws/
|
|
|
170
170
|
|
|
171
171
|
Static export generates ~85 pages:
|
|
172
172
|
- Homepage + docs + CLI + FAQ + 404
|
|
173
|
-
-
|
|
173
|
+
- 81 individual skill detail pages
|
|
174
174
|
- XML sitemap
|
|
175
175
|
|
|
176
176
|
No server needed — deploy to any static host (Vercel, Netlify, GitHub Pages, S3).
|
package/bin/cli.mjs
CHANGED
|
@@ -2,9 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
import { readdir, readFile, copyFile, mkdir, stat } from "node:fs/promises";
|
|
4
4
|
import { join, dirname } from "node:path";
|
|
5
|
-
import { createInterface } from "node:readline";
|
|
6
|
-
import { fileURLToPath } from "node:url";
|
|
7
5
|
import readline from "node:readline";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
8
7
|
|
|
9
8
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
10
9
|
const SKILLS_DIR = join(__dirname, "..", "skills");
|
|
@@ -266,142 +265,121 @@ async function detectTarget() {
|
|
|
266
265
|
return defaultTarget;
|
|
267
266
|
}
|
|
268
267
|
|
|
269
|
-
// ──
|
|
270
|
-
|
|
271
|
-
async function main() {
|
|
272
|
-
const args = process.argv.slice(2);
|
|
273
|
-
const skills = await getSkills();
|
|
274
|
-
|
|
275
|
-
await playBanner();
|
|
268
|
+
// ── Interactive Picker ───────────────────────────────────────
|
|
276
269
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
return;
|
|
270
|
+
async function interactivePick(skills) {
|
|
271
|
+
for (let i = 0; i < skills.length; i++) {
|
|
272
|
+
process.stdout.write(
|
|
273
|
+
` ${GRAY}${String(i + 1).padStart(2)}${R} ${GREEN}${skills[i].name.padEnd(24)}${R}${DIM}${skills[i].desc.slice(0, 50)}${R}\n`
|
|
274
|
+
);
|
|
283
275
|
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
rl.close();
|
|
299
|
-
|
|
300
|
-
if (answer.trim().toLowerCase() === "all") {
|
|
301
|
-
names.push(...skills.map((s) => s.name));
|
|
302
|
-
} else {
|
|
303
|
-
for (const part of answer.split(",").map((s) => s.trim()).filter(Boolean)) {
|
|
304
|
-
const num = parseInt(part);
|
|
305
|
-
if (!isNaN(num) && num >= 1 && num <= skills.length) names.push(skills[num - 1].name);
|
|
306
|
-
else names.push(part);
|
|
307
|
-
}
|
|
308
|
-
}
|
|
276
|
+
process.stdout.write(`\n ${YELLOW}Enter numbers or names (comma-separated), or 'all':${R}\n`);
|
|
277
|
+
|
|
278
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
279
|
+
const answer = await new Promise((resolve) => rl.question(` ${CYAN}> ${R}`, resolve));
|
|
280
|
+
rl.close();
|
|
281
|
+
|
|
282
|
+
const names = [];
|
|
283
|
+
if (answer.trim().toLowerCase() === "all") {
|
|
284
|
+
names.push(...skills.map((s) => s.name));
|
|
285
|
+
} else {
|
|
286
|
+
for (const part of answer.split(",").map((s) => s.trim()).filter(Boolean)) {
|
|
287
|
+
const num = parseInt(part);
|
|
288
|
+
if (!isNaN(num) && num >= 1 && num <= skills.length) names.push(skills[num - 1].name);
|
|
289
|
+
else names.push(part);
|
|
309
290
|
}
|
|
291
|
+
}
|
|
292
|
+
return names;
|
|
293
|
+
}
|
|
310
294
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
295
|
+
async function installSkills(names, skills, customDir) {
|
|
296
|
+
if (names.length === 0) {
|
|
297
|
+
process.stdout.write(` ${DIM}Nothing selected.${R}\n`);
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
315
300
|
|
|
316
|
-
|
|
317
|
-
|
|
301
|
+
const target = customDir || await detectTarget();
|
|
302
|
+
process.stdout.write(`\n ${DIM}${target}${R}\n\n`);
|
|
318
303
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
}
|
|
326
|
-
await copyDir(skill.dir, join(target, name));
|
|
327
|
-
installed++;
|
|
304
|
+
let installed = 0;
|
|
305
|
+
for (const name of names) {
|
|
306
|
+
const skill = skills.find((s) => s.name === name);
|
|
307
|
+
if (!skill) {
|
|
308
|
+
process.stdout.write(` ${YELLOW}skip${R} ${name} ${DIM}(not found)${R}\n`);
|
|
309
|
+
continue;
|
|
328
310
|
}
|
|
311
|
+
await copyDir(skill.dir, join(target, name));
|
|
312
|
+
installed++;
|
|
313
|
+
}
|
|
329
314
|
|
|
330
|
-
|
|
331
|
-
|
|
315
|
+
await playInstallProgress(installed);
|
|
316
|
+
process.stdout.write("\n");
|
|
332
317
|
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
}
|
|
318
|
+
for (const name of names) {
|
|
319
|
+
if (skills.find((s) => s.name === name)) {
|
|
320
|
+
process.stdout.write(` ${GREEN}+${R} ${name}\n`);
|
|
337
321
|
}
|
|
338
|
-
process.stdout.write(`\n ${DIM}skills.ws${R}\n\n`);
|
|
339
|
-
return;
|
|
340
322
|
}
|
|
323
|
+
process.stdout.write(`\n ${DIM}skills.ws${R}\n\n`);
|
|
324
|
+
}
|
|
341
325
|
|
|
342
|
-
|
|
343
|
-
if (!args[0] || args[0] === "help" || args[0] === "-h" || args[0] === "--help") {
|
|
344
|
-
if (args[0] === "help" || args[0] === "-h" || args[0] === "--help") {
|
|
345
|
-
process.stdout.write(` ${B}Usage:${R}\n\n`);
|
|
346
|
-
process.stdout.write(` ${CYAN}npx skills-ws${R} Interactive picker\n`);
|
|
347
|
-
process.stdout.write(` ${CYAN}npx skills-ws list${R} List all skills\n`);
|
|
348
|
-
process.stdout.write(` ${CYAN}npx skills-ws install <name>${R} Install specific skill(s)\n`);
|
|
349
|
-
process.stdout.write(` ${CYAN}npx skills-ws install all${R} Install everything\n`);
|
|
350
|
-
process.stdout.write(`\n ${DIM}${skills.length} skills | skills.ws${R}\n\n`);
|
|
351
|
-
return;
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
// Interactive picker
|
|
355
|
-
for (let i = 0; i < skills.length; i++) {
|
|
356
|
-
process.stdout.write(
|
|
357
|
-
` ${GRAY}${String(i + 1).padStart(2)}${R} ${GREEN}${skills[i].name.padEnd(24)}${R}${DIM}${skills[i].desc.slice(0, 50)}${R}\n`
|
|
358
|
-
);
|
|
359
|
-
}
|
|
360
|
-
process.stdout.write(`\n ${YELLOW}Enter numbers or names (comma-separated), or 'all':${R}\n`);
|
|
326
|
+
// ── Main ─────────────────────────────────────────────────────
|
|
361
327
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
328
|
+
async function main() {
|
|
329
|
+
const rawArgs = process.argv.slice(2);
|
|
330
|
+
const skills = await getSkills();
|
|
365
331
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
332
|
+
// Parse --dir flag from anywhere in args
|
|
333
|
+
let customDir = null;
|
|
334
|
+
const args = [];
|
|
335
|
+
for (let i = 0; i < rawArgs.length; i++) {
|
|
336
|
+
if (rawArgs[i] === "--dir" && i + 1 < rawArgs.length) {
|
|
337
|
+
customDir = rawArgs[i + 1];
|
|
338
|
+
i++; // skip next
|
|
369
339
|
} else {
|
|
370
|
-
|
|
371
|
-
const num = parseInt(part);
|
|
372
|
-
if (!isNaN(num) && num >= 1 && num <= skills.length) names.push(skills[num - 1].name);
|
|
373
|
-
else names.push(part);
|
|
374
|
-
}
|
|
340
|
+
args.push(rawArgs[i]);
|
|
375
341
|
}
|
|
342
|
+
}
|
|
376
343
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
344
|
+
await playBanner();
|
|
345
|
+
|
|
346
|
+
if (args[0] === "list" || args[0] === "ls") {
|
|
347
|
+
for (const s of skills) {
|
|
348
|
+
process.stdout.write(` ${GREEN}${s.name.padEnd(24)}${R}${DIM}${s.desc.slice(0, 55)}${R}\n`);
|
|
380
349
|
}
|
|
350
|
+
process.stdout.write(`\n ${DIM}${skills.length} skills | npx skills-ws install <name>${R}\n\n`);
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
381
353
|
|
|
382
|
-
|
|
383
|
-
|
|
354
|
+
if (args[0] === "install" || args[0] === "add") {
|
|
355
|
+
let names = args.slice(1);
|
|
384
356
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
continue;
|
|
391
|
-
}
|
|
392
|
-
await copyDir(skill.dir, join(target, name));
|
|
393
|
-
installed++;
|
|
357
|
+
// Handle "all" keyword
|
|
358
|
+
if (names.includes("all")) {
|
|
359
|
+
names = skills.map((s) => s.name);
|
|
360
|
+
} else if (names.length === 0) {
|
|
361
|
+
names = await interactivePick(skills);
|
|
394
362
|
}
|
|
395
363
|
|
|
396
|
-
await
|
|
397
|
-
|
|
364
|
+
await installSkills(names, skills, customDir);
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
398
367
|
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
}
|
|
404
|
-
process.stdout.write(
|
|
368
|
+
if (args[0] === "help" || args[0] === "-h" || args[0] === "--help") {
|
|
369
|
+
process.stdout.write(` ${B}Usage:${R}\n\n`);
|
|
370
|
+
process.stdout.write(` ${CYAN}npx skills-ws${R} Interactive picker\n`);
|
|
371
|
+
process.stdout.write(` ${CYAN}npx skills-ws list${R} List all skills\n`);
|
|
372
|
+
process.stdout.write(` ${CYAN}npx skills-ws install <name>${R} Install specific skill(s)\n`);
|
|
373
|
+
process.stdout.write(` ${CYAN}npx skills-ws install all${R} Install everything\n`);
|
|
374
|
+
process.stdout.write(` ${CYAN}npx skills-ws install --dir .${R} Install to custom directory\n`);
|
|
375
|
+
process.stdout.write(`\n ${DIM}${skills.length} skills | skills.ws${R}\n\n`);
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// No args = interactive install
|
|
380
|
+
if (!args[0]) {
|
|
381
|
+
const names = await interactivePick(skills);
|
|
382
|
+
await installSkills(names, skills, customDir);
|
|
405
383
|
return;
|
|
406
384
|
}
|
|
407
385
|
}
|
package/package.json
CHANGED
|
@@ -1,33 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skills-ws",
|
|
3
|
-
"version": "1.5.
|
|
4
|
-
"
|
|
5
|
-
"dev": "next dev",
|
|
6
|
-
"build": "next build",
|
|
7
|
-
"start": "next start",
|
|
8
|
-
"lint": "next lint"
|
|
9
|
-
},
|
|
10
|
-
"dependencies": {
|
|
11
|
-
"@vercel/analytics": "^1.6.1",
|
|
12
|
-
"next": "14.2.35",
|
|
13
|
-
"react": "^18",
|
|
14
|
-
"react-dom": "^18",
|
|
15
|
-
"react-markdown": "^10.1.0",
|
|
16
|
-
"remark-gfm": "^4.0.1",
|
|
17
|
-
"three": "^0.183.1"
|
|
18
|
-
},
|
|
19
|
-
"devDependencies": {
|
|
20
|
-
"@types/node": "^20",
|
|
21
|
-
"@types/react": "^18",
|
|
22
|
-
"@types/react-dom": "^18",
|
|
23
|
-
"@types/three": "^0.183.1",
|
|
24
|
-
"postcss": "^8",
|
|
25
|
-
"tailwindcss": "^3.4.1",
|
|
26
|
-
"typescript": "^5"
|
|
27
|
-
},
|
|
28
|
-
"description": "77 expert agent skills for AI coding assistants — marketing, growth, web3, dev, design & operations. Built for OpenClaw, Claude Code, Cursor, and Codex.",
|
|
3
|
+
"version": "1.5.1",
|
|
4
|
+
"description": "81 agent skills for AI coding assistants \u2014 marketing, growth, web3, dev, design & operations. Built for OpenClaw, Claude Code, Cursor, and Codex.",
|
|
29
5
|
"bin": {
|
|
30
|
-
"skills-ws": "bin/cli.mjs"
|
|
6
|
+
"skills-ws": "./bin/cli.mjs"
|
|
31
7
|
},
|
|
32
8
|
"keywords": [
|
|
33
9
|
"ai",
|
|
@@ -57,11 +33,24 @@
|
|
|
57
33
|
"design-system",
|
|
58
34
|
"auth"
|
|
59
35
|
],
|
|
36
|
+
"author": "Commit Media <bob@openletz.com> (https://openletz.com)",
|
|
60
37
|
"license": "MIT",
|
|
61
38
|
"repository": {
|
|
62
39
|
"type": "git",
|
|
63
40
|
"url": "https://github.com/san-npm/skills-ws"
|
|
64
41
|
},
|
|
65
42
|
"homepage": "https://skills.ws",
|
|
66
|
-
"
|
|
67
|
-
|
|
43
|
+
"bugs": {
|
|
44
|
+
"url": "https://github.com/san-npm/skills-ws/issues"
|
|
45
|
+
},
|
|
46
|
+
"files": [
|
|
47
|
+
"bin/",
|
|
48
|
+
"skills/",
|
|
49
|
+
"README.md",
|
|
50
|
+
"LICENSE",
|
|
51
|
+
"SECURITY.md"
|
|
52
|
+
],
|
|
53
|
+
"engines": {
|
|
54
|
+
"node": ">=18"
|
|
55
|
+
}
|
|
56
|
+
}
|
package/CHANGELOG.md
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
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
|