skills-ws 1.4.1 → 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.
Files changed (114) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +179 -17
  3. package/bin/cli.mjs +93 -115
  4. package/package.json +18 -29
  5. package/skills/ai-agent-building/SKILL.md +17 -19
  6. package/skills/aleph-cloud-self-deployment/SKILL.md +3711 -504
  7. package/skills/auth-implementation/SKILL.md +5 -4
  8. package/skills/ci-cd-pipeline/SKILL.md +1 -1
  9. package/skills/defi-integration/SKILL.md +8 -5
  10. package/skills/docker-production/SKILL.md +3 -2
  11. package/skills/mcp-client/SKILL.md +814 -0
  12. package/skills/mcp-server-builder/SKILL.md +1768 -0
  13. package/skills/monitoring-observability/SKILL.md +1 -1
  14. package/skills/nextjs-performance/SKILL.md +3 -2
  15. package/skills/onchain-analytics/SKILL.md +14 -9
  16. package/skills/postgres-mastery/SKILL.md +2 -3
  17. package/skills/product-led-growth/SKILL.md +7 -6
  18. package/skills/saas-billing/SKILL.md +2032 -0
  19. package/skills/solidity-dev/SKILL.md +3 -0
  20. package/skills/stripe-billing/SKILL.md +16 -16
  21. package/skills/telegram-mini-apps/SKILL.md +1860 -0
  22. package/CHANGELOG.md +0 -39
  23. package/REVIEW.md +0 -516
  24. package/app/cli/page.tsx +0 -100
  25. package/app/docs/page.tsx +0 -117
  26. package/app/faq/page.tsx +0 -92
  27. package/app/globals.css +0 -25
  28. package/app/layout.tsx +0 -248
  29. package/app/not-found.tsx +0 -22
  30. package/app/page.tsx +0 -141
  31. package/app/sitemap.ts +0 -25
  32. package/app/skills/[name]/page.tsx +0 -192
  33. package/components/AsciiBackground.tsx +0 -207
  34. package/components/FaqAccordion.tsx +0 -45
  35. package/components/InstallBox.tsx +0 -43
  36. package/components/NpmDownloads.tsx +0 -43
  37. package/components/SkillContent.tsx +0 -103
  38. package/components/SkillsGrid.tsx +0 -132
  39. package/lib/skills.ts +0 -47
  40. package/next-env.d.ts +0 -5
  41. package/next.config.mjs +0 -7
  42. package/npm-package.json +0 -56
  43. package/postcss.config.mjs +0 -8
  44. package/public/favicon.ico +0 -0
  45. package/public/favicon.svg +0 -4
  46. package/public/install.sh +0 -111
  47. package/public/llms-full.txt +0 -1000
  48. package/public/llms.txt +0 -83
  49. package/public/og.png +0 -0
  50. package/public/robots.txt +0 -51
  51. package/public/skills.json +0 -2335
  52. package/skills-data/ab-testing/SKILL.md +0 -171
  53. package/skills-data/accounting-finance/SKILL.md +0 -139
  54. package/skills-data/affiliate-marketing/SKILL.md +0 -152
  55. package/skills-data/ai-agent-design/SKILL.md +0 -207
  56. package/skills-data/api-design/SKILL.md +0 -226
  57. package/skills-data/ascii-banner/SKILL.md +0 -317
  58. package/skills-data/bing-webmaster/SKILL.md +0 -130
  59. package/skills-data/blog-engine/SKILL.md +0 -91
  60. package/skills-data/brand-strategy/SKILL.md +0 -205
  61. package/skills-data/business-development/SKILL.md +0 -140
  62. package/skills-data/cicd-pipelines/SKILL.md +0 -232
  63. package/skills-data/cold-outreach/SKILL.md +0 -169
  64. package/skills-data/community-building/SKILL.md +0 -144
  65. package/skills-data/competitor-intelligence/SKILL.md +0 -145
  66. package/skills-data/content-strategy/SKILL.md +0 -85
  67. package/skills-data/copywriting/SKILL.md +0 -88
  68. package/skills-data/crm-builder/SKILL.md +0 -86
  69. package/skills-data/crm-operations/SKILL.md +0 -148
  70. package/skills-data/customer-acquisition/SKILL.md +0 -133
  71. package/skills-data/customer-feedback/SKILL.md +0 -140
  72. package/skills-data/data-analytics/SKILL.md +0 -203
  73. package/skills-data/data-management/SKILL.md +0 -199
  74. package/skills-data/database-design/SKILL.md +0 -158
  75. package/skills-data/email-sequence/SKILL.md +0 -81
  76. package/skills-data/eu-legal-compliance/SKILL.md +0 -156
  77. package/skills-data/git-workflow/SKILL.md +0 -200
  78. package/skills-data/google-analytics/SKILL.md +0 -188
  79. package/skills-data/growth-hacking/SKILL.md +0 -75
  80. package/skills-data/hiring-team-building/SKILL.md +0 -172
  81. package/skills-data/influencer-marketing/SKILL.md +0 -181
  82. package/skills-data/landing-page-builder/SKILL.md +0 -93
  83. package/skills-data/lead-scoring/SKILL.md +0 -64
  84. package/skills-data/local-seo/SKILL.md +0 -70
  85. package/skills-data/marketing-analytics/SKILL.md +0 -106
  86. package/skills-data/mvp-launcher/SKILL.md +0 -145
  87. package/skills-data/nextjs-stack/SKILL.md +0 -231
  88. package/skills-data/page-cro/SKILL.md +0 -80
  89. package/skills-data/paid-ads/SKILL.md +0 -110
  90. package/skills-data/popup-cro/SKILL.md +0 -52
  91. package/skills-data/pr-media-outreach/SKILL.md +0 -140
  92. package/skills-data/pricing-optimization/SKILL.md +0 -316
  93. package/skills-data/programmatic-seo/SKILL.md +0 -65
  94. package/skills-data/project-management/SKILL.md +0 -161
  95. package/skills-data/prompt-engineering/SKILL.md +0 -189
  96. package/skills-data/retention-analytics/SKILL.md +0 -161
  97. package/skills-data/revenue-operations/SKILL.md +0 -162
  98. package/skills-data/sales-funnel/SKILL.md +0 -56
  99. package/skills-data/search-console/SKILL.md +0 -159
  100. package/skills-data/security-hardening/SKILL.md +0 -176
  101. package/skills-data/seo-geo/SKILL.md +0 -138
  102. package/skills-data/signup-flow-cro/SKILL.md +0 -64
  103. package/skills-data/smart-contract-auditor/SKILL.md +0 -64
  104. package/skills-data/social-media-growth/SKILL.md +0 -146
  105. package/skills-data/social-media-kit/SKILL.md +0 -56
  106. package/skills-data/testing-strategy/SKILL.md +0 -344
  107. package/skills-data/ui-ux-pro-max/SKILL.md +0 -72
  108. package/skills-data/virustotal/SKILL.md +0 -108
  109. package/skills-data/web-performance/SKILL.md +0 -219
  110. package/skills-data/webinar-events/SKILL.md +0 -148
  111. package/skills-data/yandex-webmaster/SKILL.md +0 -159
  112. package/skills.json +0 -2335
  113. package/tailwind.config.ts +0 -45
  114. 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,11 +1,12 @@
1
- # SKILLS.ws
1
+ # skills.ws
2
2
 
3
- 77 expert 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
- **Website:** [SKILLS.ws](https://skills.ws)
6
- **npm:** [npmjs.com/package/skills-ws](https://www.npmjs.com/package/skills-ws)
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)
7
6
 
8
- ## Install skills
7
+ ---
8
+
9
+ ## Quick Start
9
10
 
10
11
  ```bash
11
12
  npx skills-ws install # interactive picker
@@ -14,32 +15,193 @@ npx skills-ws install all # install everything
14
15
  npx skills-ws list # list available skills
15
16
  ```
16
17
 
17
- ## What are skills?
18
+ Skills are `SKILL.md` files that give AI coding assistants specialized knowledge — workflows, checklists, code patterns, and domain expertise. Install a skill and your agent gains expert-level capability in that domain.
19
+
20
+ ---
21
+
22
+ ## Skills (81 across 8 categories)
23
+
24
+ ### Marketing (15)
25
+ SEO/GEO, content strategy, copywriting, paid ads, email sequences, PR/media, influencer marketing, brand strategy, webinars, blog engine, and more.
26
+
27
+ ### Dev (16)
28
+ Git workflow, CI/CD, API design, database design, testing, web performance, security hardening, prompt engineering, AI agent design, MVP launcher, Next.js stack.
29
+
30
+ ### Growth (10)
31
+ Social media, community building, customer feedback, business development, cold outreach, competitor intelligence, affiliate marketing.
32
+
33
+ ### Operations (11)
34
+ EU legal compliance (GDPR, AI Act, DSA), hiring/team building, project management, CRM, accounting, revenue ops.
18
35
 
19
- Skills are `SKILL.md` files that give AI coding assistants specialized knowledge — workflows, checklists, code patterns, and domain expertise. Compatible with OpenClaw, Claude Code, Cursor, Codex, and any agent that supports the SKILL.md format.
36
+ ### Conversion (8)
37
+ Landing pages, signup flows, popups, A/B testing, pricing optimization, lead scoring, CRO, sales funnels.
20
38
 
21
- ## Categories
39
+ ### Analytics (7)
40
+ Google Analytics, Search Console, Bing/Yandex Webmaster, data analytics, retention analytics.
22
41
 
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
- - **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, 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
42
+ ### Web3 (6)
43
+ Blockchain deployment, Aleph Cloud, decentralized infrastructure.
44
+
45
+ ### Design (4)
46
+ UI/UX Pro Max, landing page builder, ASCII banner.
47
+
48
+ ---
49
+
50
+ ## How Skills Work
51
+
52
+ ```
53
+ ┌─────────────────────────────────────────┐
54
+ │ AI Coding Assistant │
55
+ │ (OpenClaw, Claude Code, Cursor, Codex) │
56
+ │ │
57
+ │ ┌───────────────────────────────────┐ │
58
+ │ │ SKILL.md files │ │
59
+ │ │ Loaded into agent context on │ │
60
+ │ │ startup — gives the agent │ │
61
+ │ │ domain expertise, workflows, │ │
62
+ │ │ checklists, and code patterns │ │
63
+ │ └───────────────────────────────────┘ │
64
+ └─────────────────────────────────────────┘
65
+ ```
66
+
67
+ 1. You install a skill via `npx skills-ws install <name>`
68
+ 2. A `SKILL.md` file is placed in your agent's skills directory
69
+ 3. Your AI assistant reads it on startup and gains that expertise
70
+ 4. Ask your assistant to do anything related to that domain — it now knows the best practices, patterns, and workflows
71
+
72
+ Skills are **markdown only** — no executable code, no runtime dependencies, no supply chain risk.
73
+
74
+ ---
75
+
76
+ ## CLI Reference
77
+
78
+ ```bash
79
+ # Interactive mode — browse and select skills
80
+ npx skills-ws install
81
+
82
+ # Install a specific skill
83
+ npx skills-ws install seo-geo
84
+
85
+ # Install multiple skills
86
+ npx skills-ws install seo-geo copywriting ab-testing
87
+
88
+ # Install all skills
89
+ npx skills-ws install all
90
+
91
+ # List available skills with categories
92
+ npx skills-ws list
93
+
94
+ # Install to a custom directory
95
+ npx skills-ws install seo-geo --dir ./my-agent/skills
96
+ ```
97
+
98
+ The CLI auto-detects your agent type (OpenClaw, Claude Code, Cursor, Codex) and installs to the correct directory.
99
+
100
+ ---
101
+
102
+ ## Website Features
103
+
104
+ The [skills.ws](https://skills.ws) website provides:
105
+
106
+ - **Searchable skill grid** — filter by category, search by name
107
+ - **Individual skill pages** — full SKILL.md content rendered as Markdown
108
+ - **One-click install commands** — copy `npx` command to clipboard
109
+ - **Live npm download counter** — monthly download stats
110
+ - **VirusTotal scan status** — every skill file is scanned
111
+
112
+ ### Keyboard Shortcuts
113
+
114
+ | Key | Action |
115
+ |-----|--------|
116
+ | `/` | Focus search |
117
+ | `Esc` | Clear search |
118
+
119
+ ---
31
120
 
32
121
  ## Development
33
122
 
34
123
  ```bash
124
+ git clone https://github.com/san-npm/skills-ws.git
125
+ cd skills-ws
35
126
  npm install
36
127
  npm run dev # http://localhost:3000
37
128
  npm run build # static export to out/
129
+ npm run lint # ESLint + Next.js linter
130
+ ```
131
+
132
+ ### Stack
133
+
134
+ - **Next.js 14** — static export (SSG), App Router
135
+ - **React 18** + TypeScript 5
136
+ - **Tailwind CSS 3.4** — dark theme
137
+ - **Three.js** — WebGL ASCII art background (homepage)
138
+ - **react-markdown** + remark-gfm — SKILL.md rendering
139
+
140
+ ### Project Structure
141
+
142
+ ```
143
+ skills-ws/
144
+ ├── app/ # Next.js App Router
145
+ │ ├── page.tsx # Homepage — ASCII hero, skill grid, stats
146
+ │ ├── skills/[name]/ # Dynamic skill detail pages (SSG)
147
+ │ ├── docs/ # How agent skills work
148
+ │ ├── cli/ # CLI reference
149
+ │ ├── faq/ # FAQ with accordion
150
+ │ └── sitemap.ts # Dynamic XML sitemap
151
+ ├── components/ # React components
152
+ │ ├── AsciiBackground.tsx # Three.js WebGL → ASCII canvas
153
+ │ ├── SkillsGrid.tsx # Searchable/filterable skill grid
154
+ │ ├── SkillContent.tsx # Markdown renderer
155
+ │ ├── InstallBox.tsx # Copy-to-clipboard install command
156
+ │ └── NpmDownloads.tsx # Live npm download counter
157
+ ├── lib/
158
+ │ └── skills.ts # Skill data access + TypeScript interfaces
159
+ ├── skills/ # Raw SKILL.md files (81 directories)
160
+ ├── public/
161
+ │ ├── skills.json # Skills database (81 skills, all metadata + content)
162
+ │ ├── llms.txt # LLM-readable skill index
163
+ │ ├── llms-full.txt # Full content dump for LLMs
164
+ │ ├── robots.txt # Crawl directives
165
+ │ └── install.sh # Bash installer script
166
+ └── skills.json # Master skills database
38
167
  ```
39
168
 
169
+ ### Build Output
170
+
171
+ Static export generates ~85 pages:
172
+ - Homepage + docs + CLI + FAQ + 404
173
+ - 81 individual skill detail pages
174
+ - XML sitemap
175
+
176
+ No server needed — deploy to any static host (Vercel, Netlify, GitHub Pages, S3).
177
+
178
+ ---
179
+
180
+ ## SEO & Structured Data
181
+
182
+ - Dynamic XML sitemap with all skill pages
183
+ - OpenGraph + Twitter Card meta tags
184
+ - JSON-LD schemas: Organization, WebSite, SoftwareApplication, BreadcrumbList, FAQPage
185
+ - Google Analytics 4 integration
186
+ - `llms.txt` + `llms-full.txt` for AI crawlers
187
+ - `robots.txt` with sitemap reference
188
+
189
+ ---
190
+
40
191
  ## Security
41
192
 
42
- See [SECURITY.md](SECURITY.md) for vulnerability reporting and security model.
193
+ Skills are **markdown files only** no executable code.
194
+
195
+ - Zero runtime dependencies (no supply chain risk)
196
+ - No `eval()`, `exec()`, or `child_process` patterns
197
+ - All skills built in-house, no third-party content
198
+ - VirusTotal scanning on all skill files
199
+ - Environment-only credentials (nothing hardcoded)
200
+ - npm package published with Sigstore provenance attestation
201
+
202
+ See [SECURITY.md](SECURITY.md) for vulnerability reporting.
203
+
204
+ ---
43
205
 
44
206
  ## License
45
207
 
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
- // ── Main ─────────────────────────────────────────────────────
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
- if (args[0] === "list" || args[0] === "ls") {
278
- for (const s of skills) {
279
- process.stdout.write(` ${GREEN}${s.name.padEnd(24)}${R}${DIM}${s.desc.slice(0, 55)}${R}\n`);
280
- }
281
- process.stdout.write(`\n ${DIM}${skills.length} skills | npx skills-ws install <name>${R}\n\n`);
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
- if (args[0] === "install" || args[0] === "add") {
286
- const names = args.slice(1);
287
-
288
- if (names.length === 0) {
289
- for (let i = 0; i < skills.length; i++) {
290
- process.stdout.write(
291
- ` ${GRAY}${String(i + 1).padStart(2)}${R} ${GREEN}${skills[i].name.padEnd(24)}${R}${DIM}${skills[i].desc.slice(0, 50)}${R}\n`
292
- );
293
- }
294
- process.stdout.write(`\n ${YELLOW}Enter numbers or names (comma-separated), or 'all':${R}\n`);
295
-
296
- const rl = createInterface({ input: process.stdin, output: process.stdout });
297
- const answer = await new Promise((resolve) => rl.question(` ${CYAN}> ${R}`, resolve));
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
- if (names.length === 0) {
312
- process.stdout.write(` ${DIM}Nothing selected.${R}\n`);
313
- return;
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
- const target = await detectTarget();
317
- process.stdout.write(`\n ${DIM}${target}${R}\n\n`);
301
+ const target = customDir || await detectTarget();
302
+ process.stdout.write(`\n ${DIM}${target}${R}\n\n`);
318
303
 
319
- let installed = 0;
320
- for (const name of names) {
321
- const skill = skills.find((s) => s.name === name);
322
- if (!skill) {
323
- process.stdout.write(` ${YELLOW}skip${R} ${name} ${DIM}(not found)${R}\n`);
324
- continue;
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
- await playInstallProgress(installed);
331
- process.stdout.write("\n");
315
+ await playInstallProgress(installed);
316
+ process.stdout.write("\n");
332
317
 
333
- for (const name of names) {
334
- if (skills.find((s) => s.name === name)) {
335
- process.stdout.write(` ${GREEN}+${R} ${name}\n`);
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
- // No args = interactive install (same as `install`)
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
- const rl = createInterface({ input: process.stdin, output: process.stdout });
363
- const answer = await new Promise((resolve) => rl.question(` ${CYAN}> ${R}`, resolve));
364
- rl.close();
328
+ async function main() {
329
+ const rawArgs = process.argv.slice(2);
330
+ const skills = await getSkills();
365
331
 
366
- const names = [];
367
- if (answer.trim().toLowerCase() === "all") {
368
- names.push(...skills.map((s) => s.name));
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
- for (const part of answer.split(",").map((s) => s.trim()).filter(Boolean)) {
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
- if (names.length === 0) {
378
- process.stdout.write(` ${DIM}Nothing selected.${R}\n`);
379
- return;
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
- const target = await detectTarget();
383
- process.stdout.write(`\n ${DIM}${target}${R}\n\n`);
354
+ if (args[0] === "install" || args[0] === "add") {
355
+ let names = args.slice(1);
384
356
 
385
- let installed = 0;
386
- for (const name of names) {
387
- const skill = skills.find((s) => s.name === name);
388
- if (!skill) {
389
- process.stdout.write(` ${YELLOW}skip${R} ${name} ${DIM}(not found)${R}\n`);
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 playInstallProgress(installed);
397
- process.stdout.write("\n");
364
+ await installSkills(names, skills, customDir);
365
+ return;
366
+ }
398
367
 
399
- for (const name of names) {
400
- if (skills.find((s) => s.name === name)) {
401
- process.stdout.write(` ${GREEN}+${R} ${name}\n`);
402
- }
403
- }
404
- process.stdout.write(`\n ${DIM}skills.ws${R}\n\n`);
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.4.1",
4
- "scripts": {
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
- "author": "skills.ws"
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
+ }
@@ -24,7 +24,7 @@ LangGraph is the production-grade choice for complex agents. It gives you explic
24
24
  ### Basic Agent with Tool Calling
25
25
 
26
26
  ```python
27
- # pip install langgraph langchain-openai
27
+ # pip install langgraph langchain-openai langgraph-checkpoint-sqlite
28
28
  from typing import Annotated, TypedDict
29
29
  from langgraph.graph import StateGraph, START, END
30
30
  from langgraph.graph.message import add_messages
@@ -306,8 +306,8 @@ def with_retry(max_retries: int = 3):
306
306
  return decorator
307
307
 
308
308
  @tool
309
- @with_timeout(30)
310
309
  @with_retry(3)
310
+ @with_timeout(30)
311
311
  async def query_database(sql: str) -> str:
312
312
  """Execute a read-only SQL query against the analytics database.
313
313
 
@@ -659,23 +659,25 @@ def sanitize_user_input(text: str) -> str:
659
659
  ### Output Validation
660
660
 
661
661
  ```python
662
- from pydantic import BaseModel, validator
662
+ from pydantic import BaseModel, field_validator
663
663
 
664
664
  class AgentResponse(BaseModel):
665
665
  answer: str
666
666
  sources: list[str]
667
667
  confidence: float
668
668
 
669
- @validator("answer")
670
- def no_system_leaks(cls, v):
669
+ @field_validator("answer")
670
+ @classmethod
671
+ def no_system_leaks(cls, v: str) -> str:
671
672
  forbidden = ["system prompt", "you are an AI", "as an AI language model"]
672
673
  for phrase in forbidden:
673
674
  if phrase.lower() in v.lower():
674
675
  raise ValueError("Response contained forbidden content")
675
676
  return v
676
677
 
677
- @validator("confidence")
678
- def valid_range(cls, v):
678
+ @field_validator("confidence")
679
+ @classmethod
680
+ def valid_range(cls, v: float) -> float:
679
681
  if not 0 <= v <= 1:
680
682
  raise ValueError("Confidence must be between 0 and 1")
681
683
  return v
@@ -783,7 +785,7 @@ MCP is the standard for connecting agents to external tools. Instead of hardcodi
783
785
  ```typescript
784
786
  // mcp-server.ts — expose tools for any MCP-compatible agent
785
787
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
786
- import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
788
+ import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
787
789
  import express from 'express';
788
790
 
789
791
  const server = new McpServer({ name: 'my-tools', version: '1.0.0' });
@@ -814,20 +816,16 @@ server.tool('create_ticket', 'Create a support ticket in Jira', {
814
816
  };
815
817
  });
816
818
 
817
- // SSE transport for remote connections
819
+ // Streamable HTTP transport (replaces deprecated SSE transport)
818
820
  const app = express();
819
- const transports: Record<string, SSEServerTransport> = {};
821
+ app.use(express.json());
820
822
 
821
- app.get('/mcp/sse', async (req, res) => {
822
- const transport = new SSEServerTransport('/mcp/messages', res);
823
- transports[transport.sessionId] = transport;
824
- res.on('close', () => delete transports[transport.sessionId]);
823
+ app.post('/mcp', async (req, res) => {
824
+ const transport = new StreamableHTTPServerTransport({
825
+ sessionIdGenerator: undefined, // stateless
826
+ });
825
827
  await server.connect(transport);
826
- });
827
-
828
- app.post('/mcp/messages', async (req, res) => {
829
- const sessionId = req.query.sessionId as string;
830
- await transports[sessionId]?.handlePostMessage(req, res);
828
+ await transport.handleRequest(req, res);
831
829
  });
832
830
 
833
831
  app.listen(3100, () => console.log('MCP server on :3100'));