@booklib/skills 1.5.1 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/CONTRIBUTING.md +23 -1
  2. package/README.md +55 -0
  3. package/benchmark/devto-post.md +178 -0
  4. package/benchmark/order-processing.original.js +158 -0
  5. package/benchmark/order-processing.pr-toolkit.js +181 -0
  6. package/benchmark/order-processing.skill-router.js +271 -0
  7. package/benchmark/review-report.md +129 -0
  8. package/bin/skills.js +327 -69
  9. package/commands/animation-at-work.md +10 -0
  10. package/commands/clean-code-reviewer.md +10 -0
  11. package/commands/data-intensive-patterns.md +10 -0
  12. package/commands/data-pipelines.md +10 -0
  13. package/commands/design-patterns.md +10 -0
  14. package/commands/domain-driven-design.md +10 -0
  15. package/commands/effective-java.md +10 -0
  16. package/commands/effective-kotlin.md +10 -0
  17. package/commands/effective-python.md +10 -0
  18. package/commands/effective-typescript.md +10 -0
  19. package/commands/kotlin-in-action.md +10 -0
  20. package/commands/lean-startup.md +10 -0
  21. package/commands/microservices-patterns.md +10 -0
  22. package/commands/programming-with-rust.md +10 -0
  23. package/commands/refactoring-ui.md +10 -0
  24. package/commands/rust-in-action.md +10 -0
  25. package/commands/skill-router.md +10 -0
  26. package/commands/spring-boot-in-action.md +10 -0
  27. package/commands/storytelling-with-data.md +10 -0
  28. package/commands/system-design-interview.md +10 -0
  29. package/commands/using-asyncio-python.md +10 -0
  30. package/commands/web-scraping-python.md +10 -0
  31. package/docs/index.html +268 -44
  32. package/package.json +4 -1
  33. package/scripts/gen-og.mjs +142 -0
  34. package/skills/skill-router/SKILL.md +23 -0
@@ -0,0 +1,10 @@
1
+ ---
2
+ description: Review microservice architecture using patterns from Chris Richardson. Usage: /microservices-patterns [file | path | description]
3
+ ---
4
+
5
+ Apply the `microservices-patterns` skill.
6
+
7
+ **Target:** $ARGUMENTS
8
+ If no target was given, run `git diff HEAD` and review those changes.
9
+
10
+ Focus on service decomposition, sagas, event sourcing, API gateways, and inter-service communication. Classify each finding as **HIGH** / **MEDIUM** / **LOW** and reference as `file:line`.
@@ -0,0 +1,10 @@
1
+ ---
2
+ description: Review Rust code against Programming with Rust (Donis Marshall). Usage: /programming-with-rust [file | path]
3
+ ---
4
+
5
+ Apply the `programming-with-rust` skill.
6
+
7
+ **Target:** $ARGUMENTS
8
+ If no target was given, run `git diff HEAD` and review those changes.
9
+
10
+ Focus on ownership, borrowing, lifetimes, traits, and safe concurrency patterns. Classify each finding as **HIGH** / **MEDIUM** / **LOW** and reference as `file:line`.
@@ -0,0 +1,10 @@
1
+ ---
2
+ description: Review UI design against Refactoring UI principles (Wathan & Schoger). Usage: /refactoring-ui [file | component | screenshot path]
3
+ ---
4
+
5
+ Apply the `refactoring-ui` skill.
6
+
7
+ **Target:** $ARGUMENTS
8
+ If no target was given, run `git diff HEAD` and review changed UI components.
9
+
10
+ Focus on visual hierarchy, spacing, typography, color, and component composition. Classify each finding as **HIGH** / **MEDIUM** / **LOW** and reference as `file:line`.
@@ -0,0 +1,10 @@
1
+ ---
2
+ description: Review Rust code using Rust in Action patterns (Tim McNamara). Usage: /rust-in-action [file | path]
3
+ ---
4
+
5
+ Apply the `rust-in-action` skill.
6
+
7
+ **Target:** $ARGUMENTS
8
+ If no target was given, run `git diff HEAD` and review those changes.
9
+
10
+ Focus on systems programming idioms: memory layout, unsafe code, FFI, and OS interaction. Classify each finding as **HIGH** / **MEDIUM** / **LOW** and reference as `file:line`.
@@ -0,0 +1,10 @@
1
+ ---
2
+ description: Route your task to the most relevant @booklib/skills skill. Usage: /skill-router [file | task description]
3
+ ---
4
+
5
+ Apply the `skill-router` skill to recommend the best @booklib skill for this task.
6
+
7
+ **Input:** $ARGUMENTS
8
+ If no input was given, use `git diff HEAD` as the scope.
9
+
10
+ Return a ranked recommendation with rationale and anti-triggers. Then ask if you should apply the recommended skill immediately.
@@ -0,0 +1,10 @@
1
+ ---
2
+ description: Review Spring Boot code using Spring Boot in Action patterns (Craig Walls). Usage: /spring-boot-in-action [file | path]
3
+ ---
4
+
5
+ Apply the `spring-boot-in-action` skill.
6
+
7
+ **Target:** $ARGUMENTS
8
+ If no target was given, run `git diff HEAD` and review those changes.
9
+
10
+ Focus on auto-configuration, dependency injection, REST endpoints, data access, and testing. Classify each finding as **HIGH** / **MEDIUM** / **LOW** and reference as `file:line`.
@@ -0,0 +1,10 @@
1
+ ---
2
+ description: Review data visualizations and charts using Storytelling with Data (Cole Nussbaumer Knaflic). Usage: /storytelling-with-data [file | chart description]
3
+ ---
4
+
5
+ Apply the `storytelling-with-data` skill.
6
+
7
+ **Target:** $ARGUMENTS
8
+ If no target was given, describe the chart or run `git diff HEAD` to review changed visualization code.
9
+
10
+ Focus on chart type choice, data-ink ratio, clutter removal, audience, and narrative. Classify each finding as **HIGH** / **MEDIUM** / **LOW**.
@@ -0,0 +1,10 @@
1
+ ---
2
+ description: Review system design using Alex Xu's framework (scalability, estimation, trade-offs). Usage: /system-design-interview [description | file]
3
+ ---
4
+
5
+ Apply the `system-design-interview` skill.
6
+
7
+ **Target:** $ARGUMENTS
8
+ If no target was given, describe the system you want reviewed or run `git diff HEAD`.
9
+
10
+ Cover requirements clarification, capacity estimation, high-level design, component deep-dive, and trade-offs. Classify each finding as **HIGH** / **MEDIUM** / **LOW**.
@@ -0,0 +1,10 @@
1
+ ---
2
+ description: Review Python async/concurrent code using Using Asyncio in Python (Caleb Hattingh). Usage: /using-asyncio-python [file | path]
3
+ ---
4
+
5
+ Apply the `using-asyncio-python` skill.
6
+
7
+ **Target:** $ARGUMENTS
8
+ If no target was given, run `git diff HEAD` and review those changes.
9
+
10
+ Focus on event loop usage, coroutine patterns, task management, cancellation, and common asyncio pitfalls. Classify each finding as **HIGH** / **MEDIUM** / **LOW** and reference as `file:line`.
@@ -0,0 +1,10 @@
1
+ ---
2
+ description: Review Python web scraping code using Web Scraping with Python (Ryan Mitchell). Usage: /web-scraping-python [file | path]
3
+ ---
4
+
5
+ Apply the `web-scraping-python` skill.
6
+
7
+ **Target:** $ARGUMENTS
8
+ If no target was given, run `git diff HEAD` and review those changes.
9
+
10
+ Focus on selector robustness, rate limiting, error handling, anti-bot evasion, and data storage. Classify each finding as **HIGH** / **MEDIUM** / **LOW** and reference as `file:line`.
package/docs/index.html CHANGED
@@ -4,10 +4,14 @@
4
4
  <meta charset="UTF-8"/>
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
6
6
  <title>booklib-ai/skills — Book-grounded AI agent skills</title>
7
- <meta name="description" content="18 AI agent skills grounded in canonical programming books. Give your AI coding assistant expert knowledge from Clean Code, Effective Java, DDD, and more."/>
7
+ <meta name="description" content="22 AI agent skills grounded in canonical programming books. Give your AI coding assistant expert knowledge from Clean Code, Effective Java, DDD, and more."/>
8
8
  <meta property="og:title" content="booklib-ai/skills"/>
9
9
  <meta property="og:description" content="Book-grounded AI agent skills for Claude Code, Cursor, Copilot, and Windsurf."/>
10
- <meta property="og:image" content="https://booklib-ai.github.io/skills/logo.png"/>
10
+ <meta property="og:image" content="https://booklib-ai.github.io/skills/og.png"/>
11
+ <meta property="og:image:width" content="1200"/>
12
+ <meta property="og:image:height" content="630"/>
13
+ <meta name="twitter:card" content="summary_large_image"/>
14
+ <meta name="twitter:image" content="https://booklib-ai.github.io/skills/og.png"/>
11
15
  <style>
12
16
  *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
13
17
 
@@ -28,7 +32,7 @@
28
32
  max-width: 720px;
29
33
  margin: 0 auto;
30
34
  }
31
- .hero img { width: 96px; height: 96px; margin-bottom: 24px; }
35
+ .hero img.logo { width: 96px; height: 96px; margin-bottom: 24px; }
32
36
  .hero h1 { font-size: 2.5rem; font-weight: 700; color: #f1f5f9; letter-spacing: -0.03em; }
33
37
  .hero p {
34
38
  font-size: 1.125rem;
@@ -40,7 +44,7 @@
40
44
  }
41
45
 
42
46
  /* Install */
43
- .install {
47
+ #install {
44
48
  display: flex;
45
49
  align-items: center;
46
50
  justify-content: center;
@@ -58,6 +62,11 @@
58
62
  color: #a5b4fc;
59
63
  cursor: pointer;
60
64
  user-select: all;
65
+ transition: border-color 0.2s;
66
+ }
67
+ .install-box.highlighted {
68
+ border-color: #6366f1;
69
+ color: #c7d2fe;
61
70
  }
62
71
  .copy-btn {
63
72
  background: #6366f1;
@@ -84,7 +93,7 @@
84
93
 
85
94
  /* Skills grid */
86
95
  .skills-section {
87
- max-width: 900px;
96
+ max-width: 1100px;
88
97
  margin: 64px auto;
89
98
  padding: 0 24px;
90
99
  }
@@ -92,28 +101,126 @@
92
101
  font-size: 1.5rem;
93
102
  font-weight: 700;
94
103
  color: #f1f5f9;
95
- margin-bottom: 24px;
104
+ margin-bottom: 8px;
105
+ text-align: center;
106
+ }
107
+ .skills-section .subtitle {
96
108
  text-align: center;
109
+ color: #64748b;
110
+ font-size: 0.9rem;
111
+ margin-bottom: 32px;
97
112
  }
98
113
  .skills-grid {
99
114
  display: grid;
100
- grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
101
- gap: 16px;
115
+ grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
116
+ gap: 14px;
102
117
  }
118
+
119
+ /* Card */
103
120
  .skill-card {
104
121
  background: #11111f;
105
122
  border: 1px solid #1e1e35;
106
123
  border-radius: 12px;
107
- padding: 20px;
108
- transition: border-color 0.15s, transform 0.15s;
124
+ overflow: hidden;
125
+ cursor: pointer;
126
+ transition: border-color 0.15s, transform 0.15s, box-shadow 0.15s;
127
+ display: flex;
128
+ flex-direction: column;
129
+ text-decoration: none;
130
+ color: inherit;
109
131
  }
110
132
  .skill-card:hover {
111
133
  border-color: #6366f1;
112
- transform: translateY(-2px);
134
+ transform: translateY(-3px);
135
+ box-shadow: 0 8px 24px rgba(99, 102, 241, 0.15);
136
+ text-decoration: none;
137
+ }
138
+ .skill-card.active {
139
+ border-color: #818cf8;
140
+ box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.3);
141
+ }
142
+
143
+ /* Book cover area */
144
+ .cover-wrap {
145
+ width: 100%;
146
+ aspect-ratio: 2 / 3;
147
+ background: #161625;
148
+ display: flex;
149
+ align-items: center;
150
+ justify-content: center;
151
+ overflow: hidden;
152
+ position: relative;
153
+ }
154
+ .cover-wrap img {
155
+ width: 100%;
156
+ height: 100%;
157
+ object-fit: cover;
158
+ display: block;
159
+ }
160
+ .cover-wrap img.loading {
161
+ background: linear-gradient(90deg, #161625 25%, #1e1e38 50%, #161625 75%);
162
+ background-size: 200% 100%;
163
+ animation: shimmer 1.5s infinite linear;
164
+ }
165
+ @keyframes shimmer {
166
+ 0% { background-position: 200% 0; }
167
+ 100% { background-position: -200% 0; }
168
+ }
169
+ .cover-fallback {
170
+ width: 100%;
171
+ height: 100%;
172
+ display: flex;
173
+ flex-direction: column;
174
+ align-items: center;
175
+ justify-content: center;
176
+ padding: 16px;
177
+ text-align: center;
178
+ gap: 8px;
179
+ }
180
+ .cover-fallback .initials {
181
+ font-size: 2rem;
182
+ font-weight: 700;
183
+ color: #6366f1;
184
+ line-height: 1;
185
+ }
186
+ .cover-fallback .fallback-title {
187
+ font-size: 0.75rem;
188
+ color: #64748b;
189
+ line-height: 1.3;
190
+ }
191
+
192
+ /* Card body */
193
+ .card-body {
194
+ padding: 10px 12px 12px;
195
+ flex: 1;
196
+ display: flex;
197
+ flex-direction: column;
198
+ gap: 3px;
199
+ }
200
+ .card-body .skill-name {
201
+ font-size: 0.7rem;
202
+ font-weight: 700;
203
+ color: #a5b4fc;
204
+ font-family: "SF Mono", "Fira Code", monospace;
205
+ word-break: break-all;
206
+ }
207
+ .card-body .book-title {
208
+ font-size: 0.75rem;
209
+ font-weight: 600;
210
+ color: #e2e8f0;
211
+ line-height: 1.3;
212
+ margin-top: 2px;
213
+ }
214
+ .card-body .book-author {
215
+ font-size: 0.68rem;
216
+ color: #64748b;
217
+ }
218
+ .card-body .card-desc {
219
+ font-size: 0.68rem;
220
+ color: #475569;
221
+ line-height: 1.4;
222
+ margin-top: 4px;
113
223
  }
114
- .skill-card .icon { font-size: 1.5rem; margin-bottom: 10px; }
115
- .skill-card h3 { font-size: 0.95rem; font-weight: 600; color: #e2e8f0; margin-bottom: 6px; }
116
- .skill-card p { font-size: 0.825rem; color: #64748b; line-height: 1.5; }
117
224
 
118
225
  /* Footer */
119
226
  footer {
@@ -129,13 +236,13 @@
129
236
  <body>
130
237
 
131
238
  <section class="hero">
132
- <img src="https://raw.githubusercontent.com/booklib-ai/skills/main/assets/logo.svg" alt="booklib-ai skills logo"/>
239
+ <img class="logo" src="https://raw.githubusercontent.com/booklib-ai/skills/main/assets/logo.svg" alt="booklib-ai skills logo"/>
133
240
  <h1>Skills</h1>
134
241
  <p>Book-grounded AI agent skills — expert knowledge from canonical programming books, packaged for Claude Code, Cursor, Copilot, and Windsurf.</p>
135
242
 
136
- <div class="install">
243
+ <div id="install">
137
244
  <div class="install-box" id="cmd">npx skills add booklib-ai/skills --all -g</div>
138
- <button class="copy-btn" onclick="copy()">Copy</button>
245
+ <button class="copy-btn" onclick="copyCmd()">Copy</button>
139
246
  </div>
140
247
 
141
248
  <div class="badges">
@@ -147,40 +254,157 @@
147
254
  </section>
148
255
 
149
256
  <section class="skills-section">
150
- <h2>18 skills, 18 books</h2>
151
- <div class="skills-grid">
152
- <div class="skill-card"><div class="icon">🎬</div><h3>animation-at-work</h3><p>Web animation principles from Rachel Nabors — motion perception, 12 animation principles, performance.</p></div>
153
- <div class="skill-card"><div class="icon">🧹</div><h3>clean-code-reviewer</h3><p>Code review against Robert C. Martin's Clean Code — naming, functions, comments, classes.</p></div>
154
- <div class="skill-card"><div class="icon">🗄️</div><h3>data-intensive-patterns</h3><p>Reliable, scalable systems from Martin Kleppmann — storage engines, replication, transactions.</p></div>
155
- <div class="skill-card"><div class="icon">🔀</div><h3>data-pipelines</h3><p>Pipeline practices from James Densmore — ingestion, streaming, transformation, orchestration.</p></div>
156
- <div class="skill-card"><div class="icon">🏗️</div><h3>design-patterns</h3><p>GoF design patterns from Head First Design Patterns — creational, structural, behavioral.</p></div>
157
- <div class="skill-card"><div class="icon">🧩</div><h3>domain-driven-design</h3><p>Eric Evans' DDD — Aggregates, Value Objects, Bounded Contexts, Ubiquitous Language.</p></div>
158
- <div class="skill-card"><div class="icon">☕</div><h3>effective-java</h3><p>Joshua Bloch's Effective Java — object creation, generics, enums, lambdas, concurrency.</p></div>
159
- <div class="skill-card"><div class="icon">🛡️</div><h3>effective-kotlin</h3><p>Marcin Moskała's Effective Kotlin — safety, readability, reusability, abstraction.</p></div>
160
- <div class="skill-card"><div class="icon">🐍</div><h3>effective-python</h3><p>Brett Slatkin's Effective Python — Pythonic thinking, functions, classes, concurrency.</p></div>
161
- <div class="skill-card"><div class="icon">⚡</div><h3>kotlin-in-action</h3><p>Kotlin in Action — functions, classes, lambdas, nullability, coroutines, flows.</p></div>
162
- <div class="skill-card"><div class="icon">🚀</div><h3>lean-startup</h3><p>Eric Ries' The Lean Startup — MVP testing, validated learning, Build-Measure-Learn.</p></div>
163
- <div class="skill-card"><div class="icon">🔧</div><h3>microservices-patterns</h3><p>Chris Richardson — decomposition, sagas, API gateways, event sourcing, CQRS.</p></div>
164
- <div class="skill-card"><div class="icon">🎨</div><h3>refactoring-ui</h3><p>Refactoring UI by Wathan &amp; Schoger — visual hierarchy, layout, typography, color.</p></div>
165
- <div class="skill-card"><div class="icon">🗺️</div><h3>skill-router</h3><p><strong>Meta-skill.</strong> Automatically selects the 1–2 most relevant skills for any task.</p></div>
166
- <div class="skill-card"><div class="icon">📊</div><h3>storytelling-with-data</h3><p>Cole Nussbaumer Knaflic — effective visuals, decluttering, narrative structure.</p></div>
167
- <div class="skill-card"><div class="icon">🏛️</div><h3>system-design-interview</h3><p>Alex Xu — scaling, estimation, load balancing, caching, sharding, real-world designs.</p></div>
168
- <div class="skill-card"><div class="icon">🔄</div><h3>using-asyncio-python</h3><p>Caleb Hattingh — coroutines, event loop, tasks, signal handling, aiohttp.</p></div>
169
- <div class="skill-card"><div class="icon">🕷️</div><h3>web-scraping-python</h3><p>Ryan Mitchell — BeautifulSoup, Scrapy, Selenium, data storage, anti-detection.</p></div>
170
- </div>
257
+ <h2>22 skills, 22 books</h2>
258
+ <p class="subtitle">Click any skill to see its install command</p>
259
+ <div class="skills-grid" id="grid"></div>
171
260
  </section>
172
261
 
173
262
  <footer>
174
- <p>MIT License · <a href="https://github.com/booklib-ai/skills">GitHub</a> · <a href="https://github.com/booklib-ai/skills/blob/main/CONTRIBUTING.md">Contributing</a> · <a href="https://github.com/booklib-ai/skills/blob/main/AGENTS.md">Agent Setup</a></p>
263
+ <p>MIT License &middot; <a href="https://github.com/booklib-ai/skills">GitHub</a> &middot; <a href="https://github.com/booklib-ai/skills/blob/main/CONTRIBUTING.md">Contributing</a> &middot; <a href="https://github.com/booklib-ai/skills/blob/main/AGENTS.md">Agent Setup</a></p>
175
264
  </footer>
176
265
 
177
266
  <script>
178
- function copy() {
179
- navigator.clipboard.writeText(document.getElementById('cmd').textContent);
180
- const btn = document.querySelector('.copy-btn');
181
- btn.textContent = 'Copied!';
182
- setTimeout(() => btn.textContent = 'Copy', 2000);
267
+ const SKILLS = [
268
+ { name: "animation-at-work", book: "Animation at Work", author: "Rachel Nabors", isbn: "9781937557942", desc: "Motion perception, 12 animation principles, CSS transitions, and performance." },
269
+ { name: "clean-code-reviewer", book: "Clean Code", author: "Robert C. Martin", isbn: "9780132350884", desc: "Naming, functions, comments, classes, and the Boy Scout Rule." },
270
+ { name: "data-intensive-patterns",book: "Designing Data-Intensive Applications",author: "Martin Kleppmann", isbn: "9781449373320", desc: "Storage engines, replication, transactions, and distributed systems." },
271
+ { name: "data-pipelines", book: "Data Pipelines Pocket Reference", author: "James Densmore", isbn: "9781492087601", desc: "Ingestion, streaming, transformation, and orchestration." },
272
+ { name: "design-patterns", book: "Head First Design Patterns", author: "Freeman & Robson", isbn: "9781492078005", desc: "GoF creational, structural, and behavioral patterns in depth." },
273
+ { name: "domain-driven-design", book: "Domain-Driven Design", author: "Eric Evans", isbn: "9780321125217", desc: "Aggregates, Value Objects, Bounded Contexts, Ubiquitous Language." },
274
+ { name: "effective-java", book: "Effective Java", author: "Joshua Bloch", isbn: "9780134685991", desc: "Object creation, generics, enums, lambdas, and concurrency." },
275
+ { name: "effective-kotlin", book: "Effective Kotlin", author: "Marcin Moskala", isbn: "9781803248776", desc: "Safety, readability, reusability, and abstraction." },
276
+ { name: "effective-python", book: "Effective Python", author: "Brett Slatkin", isbn: "9780134853987", desc: "Pythonic thinking, functions, classes, concurrency, and testing." },
277
+ { name: "effective-typescript", book: "Effective TypeScript", author: "Dan Vanderkam", isbn: "9781492053743", desc: "Type system, type design, avoiding any, declarations, and migration." },
278
+ { name: "kotlin-in-action", book: "Kotlin in Action", author: "Elizarov & Isakova", isbn: "9781617293290", desc: "Functions, classes, lambdas, nullability, coroutines, and flows." },
279
+ { name: "lean-startup", book: "The Lean Startup", author: "Eric Ries", isbn: "9780307887894", desc: "MVP testing, validated learning, Build-Measure-Learn loop." },
280
+ { name: "microservices-patterns", book: "Microservices Patterns", author: "Chris Richardson", isbn: "9781617294549", desc: "Decomposition, sagas, API gateways, event sourcing, and CQRS." },
281
+ { name: "programming-with-rust", book: "Programming with Rust", author: "Donis Marshall", isbn: "9780137889655", desc: "Ownership, borrowing, lifetimes, error handling, traits, concurrency." },
282
+ { name: "refactoring-ui", book: "Refactoring UI", author: "Wathan & Schoger", isbn: null, desc: "Visual hierarchy, layout, typography, color, and spacing." },
283
+ { name: "rust-in-action", book: "Rust in Action", author: "Tim McNamara", isbn: "9781617294556", desc: "Systems programming — smart pointers, memory, networking, OS." },
284
+ { name: "skill-router", book: "Meta-skill", author: "booklib-ai", isbn: null, desc: "Automatically routes to the most relevant skill for any task." },
285
+ { name: "spring-boot-in-action", book: "Spring Boot in Action", author: "Craig Walls", isbn: "9781617292545", desc: "Auto-configuration, starters, testing, Actuator, and deployment." },
286
+ { name: "storytelling-with-data", book: "Storytelling with Data", author: "Cole Nussbaumer Knaflic",isbn: "9781119002253", desc: "Effective visuals, decluttering, and narrative structure." },
287
+ { name: "system-design-interview",book: "System Design Interview", author: "Alex Xu", isbn: "9798664653403", desc: "Scaling, estimation, load balancing, caching, and sharding." },
288
+ { name: "using-asyncio-python", book: "Using Asyncio in Python", author: "Caleb Hattingh", isbn: "9781492075325", desc: "Coroutines, event loop, tasks, and signal handling." },
289
+ { name: "web-scraping-python", book: "Web Scraping with Python", author: "Ryan Mitchell", isbn: "9781491985564", desc: "BeautifulSoup, Scrapy, Selenium, and data storage." },
290
+ ];
291
+
292
+ const ALL_CMD = "npx skills add booklib-ai/skills --all -g";
293
+ let activeCard = null;
294
+
295
+ function initials(name) {
296
+ return name.split(/[\s-]+/).map(w => w[0]).join("").toUpperCase().slice(0, 3);
183
297
  }
298
+
299
+ // Fetch cover URL from Google Books JSON API.
300
+ // Using the API (not direct hotlinking) avoids false-positive placeholder images
301
+ // ("No preview available" hatch / "image not available" text) that Google returns
302
+ // as HTTP 200 responses — the API simply omits imageLinks when no cover exists.
303
+ function showFb(img) {
304
+ img.style.display = "none";
305
+ const fb = img.nextElementSibling;
306
+ if (fb) fb.style.display = "flex";
307
+ }
308
+
309
+ async function loadCover(img) {
310
+ const isbn = img.dataset.isbn;
311
+ try {
312
+ const url = `https://www.googleapis.com/books/v1/volumes?q=isbn:${isbn}&fields=items(volumeInfo(imageLinks))&maxResults=1`;
313
+ const d = await fetch(url).then(r => r.json());
314
+ const links = d.items?.[0]?.volumeInfo?.imageLinks;
315
+ // thumbnail/smallThumbnail are the only sizes returned by a search query.
316
+ // Replacing zoom=1 with zoom=0 fetches the largest available version of the same image.
317
+ const src = (links?.thumbnail || links?.smallThumbnail || "")
318
+ .replace(/^http:/, "https:")
319
+ .replace("zoom=1", "zoom=5")
320
+ .replace("&edge=curl", "");
321
+ if (src) {
322
+ img.onload = () => img.classList.remove("loading");
323
+ img.onerror = () => showFb(img);
324
+ img.src = src;
325
+ } else {
326
+ showFb(img);
327
+ }
328
+ } catch {
329
+ showFb(img);
330
+ }
331
+ }
332
+
333
+ function buildCard(skill) {
334
+ const card = document.createElement("a");
335
+ card.className = "skill-card";
336
+ card.href = `https://github.com/booklib-ai/skills/tree/main/skills/${skill.name}`;
337
+ card.target = "_blank";
338
+ card.rel = "noopener";
339
+
340
+ const coverHtml = skill.isbn
341
+ ? `<img
342
+ class="loading"
343
+ data-isbn="${skill.isbn}"
344
+ alt="${skill.book} cover"
345
+ />
346
+ <div class="cover-fallback" style="display:none">
347
+ <div class="initials">${initials(skill.book)}</div>
348
+ <div class="fallback-title">${skill.book}</div>
349
+ </div>`
350
+ : `<div class="cover-fallback">
351
+ <div class="initials">${initials(skill.book)}</div>
352
+ <div class="fallback-title">${skill.book}</div>
353
+ </div>`;
354
+
355
+ card.innerHTML = `
356
+ <div class="cover-wrap">${coverHtml}</div>
357
+ <div class="card-body">
358
+ <div class="skill-name">${skill.name}</div>
359
+ <div class="book-title">${skill.book}</div>
360
+ <div class="book-author">${skill.author}</div>
361
+ <div class="card-desc">${skill.desc}</div>
362
+ </div>
363
+ `;
364
+
365
+ card.addEventListener("click", (e) => {
366
+ e.preventDefault();
367
+ selectSkill(skill, card);
368
+ });
369
+
370
+ return card;
371
+ }
372
+
373
+ function selectSkill(skill, card) {
374
+ // Deactivate previous
375
+ if (activeCard && activeCard !== card) {
376
+ activeCard.classList.remove("active");
377
+ }
378
+ const cmdEl = document.getElementById("cmd");
379
+
380
+ if (activeCard === card) {
381
+ // Deselect — back to install all
382
+ activeCard.classList.remove("active");
383
+ activeCard = null;
384
+ cmdEl.textContent = ALL_CMD;
385
+ cmdEl.classList.remove("highlighted");
386
+ } else {
387
+ activeCard = card;
388
+ card.classList.add("active");
389
+ cmdEl.textContent = `npx skills add booklib-ai/skills ${skill.name} -g`;
390
+ cmdEl.classList.add("highlighted");
391
+ document.getElementById("install").scrollIntoView({ behavior: "smooth", block: "center" });
392
+ }
393
+ }
394
+
395
+ function copyCmd() {
396
+ const text = document.getElementById("cmd").textContent;
397
+ navigator.clipboard.writeText(text);
398
+ const btn = document.querySelector(".copy-btn");
399
+ btn.textContent = "Copied!";
400
+ setTimeout(() => btn.textContent = "Copy", 2000);
401
+ }
402
+
403
+ // Build grid
404
+ const grid = document.getElementById("grid");
405
+ SKILLS.forEach(skill => grid.appendChild(buildCard(skill)));
406
+ // Kick off async cover loading after DOM is populated
407
+ document.querySelectorAll("img[data-isbn]").forEach(loadCover);
184
408
  </script>
185
409
 
186
410
  </body>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@booklib/skills",
3
- "version": "1.5.1",
3
+ "version": "1.6.0",
4
4
  "description": "Book knowledge distilled into structured AI skills for Claude Code and other AI assistants",
5
5
  "bin": {
6
6
  "skills": "bin/skills.js"
@@ -20,5 +20,8 @@
20
20
  },
21
21
  "engines": {
22
22
  "node": ">=16"
23
+ },
24
+ "devDependencies": {
25
+ "puppeteer": "^24.39.1"
23
26
  }
24
27
  }