@ericrisco/rsc 1.0.27 → 1.0.29
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/README.md +22 -4
- package/manifest.json +230 -2
- package/package.json +1 -1
- package/scripts/detect-repo.js +27 -1
- package/scripts/drift-check.js +40 -5
- package/scripts/lib/domains.js +3 -2
- package/skills/animate/SKILL.md +228 -0
- package/skills/animate/evals/cases.yaml +36 -0
- package/skills/animate/references/recipes.md +324 -0
- package/skills/animate-expo/SKILL.md +281 -0
- package/skills/animate-expo/evals/cases.yaml +36 -0
- package/skills/animate-expo/references/recipes.md +385 -0
- package/skills/animation-vocabulary/SKILL.md +189 -0
- package/skills/animation-vocabulary/evals/cases.yaml +31 -0
- package/skills/apple-design/SKILL.md +301 -0
- package/skills/apple-design/evals/cases.yaml +33 -0
- package/skills/ask-sonner/SKILL.md +104 -0
- package/skills/ask-sonner/evals/cases.yaml +33 -0
- package/skills/ask-sonner/references/api.md +64 -0
- package/skills/design/SKILL.md +8 -0
- package/skills/design/references/motion-and-interaction.md +14 -3
- package/skills/design/references/visual-system.md +4 -3
- package/skills/design-eng/SKILL.md +724 -0
- package/skills/design-eng/evals/cases.yaml +36 -0
- package/skills/expo/SKILL.md +6 -0
- package/skills/find-animation-opportunities/SKILL.md +150 -0
- package/skills/find-animation-opportunities/evals/cases.yaml +31 -0
- package/skills/improve-animations/SKILL.md +126 -0
- package/skills/improve-animations/evals/cases.yaml +31 -0
- package/skills/improve-animations/references/audit.md +115 -0
- package/skills/improve-animations/references/plan-template.md +73 -0
- package/skills/pick-ui-library/SKILL.md +100 -0
- package/skills/pick-ui-library/evals/cases.yaml +33 -0
- package/skills/prototype/SKILL.md +113 -0
- package/skills/prototype/evals/cases.yaml +31 -0
- package/skills/prototype/references/picker.md +197 -0
- package/skills/react/SKILL.md +6 -0
- package/skills/react-native/SKILL.md +5 -0
- package/skills/review-animations/SKILL.md +137 -0
- package/skills/review-animations/evals/cases.yaml +34 -0
- package/skills/review-animations/references/standards.md +187 -0
- package/skills/review-animations/scripts/verify.sh +164 -0
- package/skills/swift-ios/SKILL.md +7 -0
- package/skills/write-swift/SKILL.md +413 -0
- package/skills/write-swift/evals/cases.yaml +36 -0
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
|
|
3
|
-
<img src="https://raw.githubusercontent.com/ericrisco/rsc-harness/main/site/og.png" alt="rsc — your agent needs a memory (02-DOCS/, or it invents what it cannot remember), arms (01-TOOLS/, or it never touches your database), a trade (
|
|
3
|
+
<img src="https://raw.githubusercontent.com/ericrisco/rsc-harness/main/site/og.png" alt="rsc — your agent needs a memory (02-DOCS/, or it invents what it cannot remember), arms (01-TOOLS/, or it never touches your database), a trade (276 skills, or it guesses how the job is done), and reflexes (deterministic hooks, or it forgets the rule mid-session). One meta-harness for 17 coding assistants." width="960">
|
|
4
4
|
|
|
5
|
-
# `rsc` —
|
|
5
|
+
# `rsc` — 276 agent skills, one CLI, zero bloat
|
|
6
6
|
|
|
7
7
|
[](https://www.npmjs.com/package/@ericrisco/rsc)
|
|
8
8
|
[](https://www.npmjs.com/package/@ericrisco/rsc)
|
|
@@ -344,11 +344,11 @@ Train and adapt open models end to end: classic ML, deep learning, NLP, fine-tun
|
|
|
344
344
|
|
|
345
345
|
### 🗣️ Languages
|
|
346
346
|
|
|
347
|
-
[typescript](skills/typescript/) · [python](skills/python/) · [java](skills/java/) · [csharp-dotnet](skills/csharp-dotnet/) · [php](skills/php/) · [ruby](skills/ruby/) · [cpp](skills/cpp/) · [elixir](skills/elixir/) · [bash-scripting](skills/bash-scripting/) · [sql](skills/sql/) · [go](skills/go/)
|
|
347
|
+
[typescript](skills/typescript/) · [python](skills/python/) · [java](skills/java/) · [csharp-dotnet](skills/csharp-dotnet/) · [php](skills/php/) · [ruby](skills/ruby/) · [cpp](skills/cpp/) · [elixir](skills/elixir/) · [bash-scripting](skills/bash-scripting/) · [sql](skills/sql/) · [go](skills/go/) · [write-swift](skills/write-swift/)
|
|
348
348
|
|
|
349
349
|
### 🏗️ Frameworks & app stacks
|
|
350
350
|
|
|
351
|
-
[fastapi](skills/fastapi/) · [nextjs](skills/nextjs/) · [react](skills/react/) · [react-native](skills/react-native/) · [vue-nuxt](skills/vue-nuxt/) · [angular](skills/angular/) · [svelte](skills/svelte/) · [astro](skills/astro/) · [solid-js](skills/solid-js/) · [htmx](skills/htmx/) · [nodejs](skills/nodejs/) · [nestjs](skills/nestjs/) · [django](skills/django/) · [laravel](skills/laravel/) · [rails](skills/rails/) · [spring-boot](skills/spring-boot/) · [phoenix](skills/phoenix/) · [flutter](skills/flutter/) · [swift-ios](skills/swift-ios/) · [kotlin-android](skills/kotlin-android/) · [compose-multiplatform](skills/compose-multiplatform/) · [expo](skills/expo/) · [tauri](skills/tauri/) · [electron](skills/electron/) · [rust](skills/rust/) · [wordpress](skills/wordpress/) · [shopify](skills/shopify/) · [no-code-app](skills/no-code-app/) · [chrome-extension](skills/chrome-extension/) · [api-design](skills/api-design/)
|
|
351
|
+
[fastapi](skills/fastapi/) · [nextjs](skills/nextjs/) · [react](skills/react/) · [react-native](skills/react-native/) · [vue-nuxt](skills/vue-nuxt/) · [angular](skills/angular/) · [svelte](skills/svelte/) · [astro](skills/astro/) · [solid-js](skills/solid-js/) · [htmx](skills/htmx/) · [nodejs](skills/nodejs/) · [nestjs](skills/nestjs/) · [django](skills/django/) · [laravel](skills/laravel/) · [rails](skills/rails/) · [spring-boot](skills/spring-boot/) · [phoenix](skills/phoenix/) · [flutter](skills/flutter/) · [swift-ios](skills/swift-ios/) · [kotlin-android](skills/kotlin-android/) · [compose-multiplatform](skills/compose-multiplatform/) · [expo](skills/expo/) · [tauri](skills/tauri/) · [electron](skills/electron/) · [rust](skills/rust/) · [wordpress](skills/wordpress/) · [shopify](skills/shopify/) · [no-code-app](skills/no-code-app/) · [chrome-extension](skills/chrome-extension/) · [api-design](skills/api-design/) · [pick-ui-library](skills/pick-ui-library/) · [ask-sonner](skills/ask-sonner/)
|
|
352
352
|
|
|
353
353
|
### 🎮 Game development
|
|
354
354
|
|
|
@@ -372,6 +372,10 @@ Three engines + engine-agnostic disciplines. Every engine skill pins the current
|
|
|
372
372
|
|
|
373
373
|
[code-review](skills/code-review/) · [security-scan](skills/security-scan/) · [secure-coding](skills/secure-coding/) · [testing-py](skills/testing-py/) · [testing-web](skills/testing-web/) · [testing-go](skills/testing-go/) · [e2e-testing](skills/e2e-testing/) · [accessibility](skills/accessibility/) · [performance](skills/performance/) · [error-handling](skills/error-handling/) · [observability](skills/observability/)
|
|
374
374
|
|
|
375
|
+
### 🌀 Motion & interface craft
|
|
376
|
+
|
|
377
|
+
[design-eng](skills/design-eng/) · [animate](skills/animate/) · [animate-expo](skills/animate-expo/) · [review-animations](skills/review-animations/) · [improve-animations](skills/improve-animations/) · [find-animation-opportunities](skills/find-animation-opportunities/) · [animation-vocabulary](skills/animation-vocabulary/) · [apple-design](skills/apple-design/) · [prototype](skills/prototype/)
|
|
378
|
+
|
|
375
379
|
### 🎨 Design & content craft
|
|
376
380
|
|
|
377
381
|
[design](skills/design/) · [presentations](skills/presentations/) · [course-storytelling](skills/course-storytelling/) · [course-builder](skills/course-builder/) · [technical-writing](skills/technical-writing/) · [translation-l10n](skills/translation-l10n/)
|
|
@@ -455,6 +459,20 @@ the rubric to hold it to is `scripts/skill-rubric.md`.
|
|
|
455
459
|
This is a personal catalog. Bug reports welcome via GitHub issues; PRs fixing
|
|
456
460
|
detector patterns, provider endpoints, or typos are appreciated.
|
|
457
461
|
|
|
462
|
+
## Third-party skills
|
|
463
|
+
|
|
464
|
+
Most of this catalog is written here. These are not, and they keep their author's credit:
|
|
465
|
+
|
|
466
|
+
| Skills | Source | License |
|
|
467
|
+
| --- | --- | --- |
|
|
468
|
+
| `design-eng` · `animate` · `animate-expo` · `review-animations` · `improve-animations` · `find-animation-opportunities` · `animation-vocabulary` · `apple-design` · `prototype` · `pick-ui-library` · `write-swift` · `ask-sonner` | [emilkowalski/skills](https://github.com/emilkowalski/skills) by Emil Kowalski, commit `d23d7f8` | MIT |
|
|
469
|
+
| part of the AI-tell corpus in `design` | [Leonxlnx/taste-skill](https://github.com/Leonxlnx/taste-skill) | MIT |
|
|
470
|
+
|
|
471
|
+
Adapted, not mirrored: each one carries rsc frontmatter, routing evals, hand-offs to its siblings
|
|
472
|
+
and — where it declares a binding rule — a checker with a test. The craft bar in them is the
|
|
473
|
+
original author's. If you want the source of the motion material rather than this adaptation, go to
|
|
474
|
+
[animations.dev](https://animations.dev/).
|
|
475
|
+
|
|
458
476
|
## License
|
|
459
477
|
|
|
460
478
|
MIT. See [LICENSE](LICENSE).
|
package/manifest.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.0.
|
|
2
|
+
"version": "1.0.29",
|
|
3
3
|
"counts": {
|
|
4
|
-
"skills":
|
|
4
|
+
"skills": 276
|
|
5
5
|
},
|
|
6
6
|
"skills": [
|
|
7
7
|
{
|
|
@@ -182,6 +182,62 @@
|
|
|
182
182
|
],
|
|
183
183
|
"profiles": []
|
|
184
184
|
},
|
|
185
|
+
{
|
|
186
|
+
"id": "animate",
|
|
187
|
+
"description": "Build a web animation: whether it should animate at all, the purpose, the tool, the properties, the easing curve, the duration, interruption and exit. Writes the CSS or Motion code for dropdowns, modals, toasts, tooltips, accordions, press feedback, stagger and scroll reveals. Use to animate something or make a component feel alive.",
|
|
188
|
+
"tags": [
|
|
189
|
+
"motion",
|
|
190
|
+
"animation",
|
|
191
|
+
"css",
|
|
192
|
+
"transitions",
|
|
193
|
+
"ui"
|
|
194
|
+
],
|
|
195
|
+
"recommends": [
|
|
196
|
+
"review-animations",
|
|
197
|
+
"pick-ui-library",
|
|
198
|
+
"apple-design"
|
|
199
|
+
],
|
|
200
|
+
"profiles": [
|
|
201
|
+
"full"
|
|
202
|
+
]
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
"id": "animate-expo",
|
|
206
|
+
"description": "Build animation and gestures in React Native and Expo with Reanimated worklets on the UI thread — sheets, drawers, screen transitions, swipe, drag, press feedback, haptics. Use when adding gestures to an Expo app, or when motion stutters, janks or drops frames on a real Android or iOS device.",
|
|
207
|
+
"tags": [
|
|
208
|
+
"motion",
|
|
209
|
+
"animation",
|
|
210
|
+
"expo",
|
|
211
|
+
"react-native",
|
|
212
|
+
"gestures"
|
|
213
|
+
],
|
|
214
|
+
"recommends": [
|
|
215
|
+
"expo",
|
|
216
|
+
"react-native",
|
|
217
|
+
"animate"
|
|
218
|
+
],
|
|
219
|
+
"profiles": [
|
|
220
|
+
"full"
|
|
221
|
+
]
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
"id": "animation-vocabulary",
|
|
225
|
+
"description": "Reverse glossary: turn a vague description of a motion effect into its exact name — a popover growing from its trigger is origin-aware, iOS overscroll is rubber-banding, items appearing one after another with a delay is a stagger. Use for \\\"what's it called when…\\\" or \\\"what do you call it when…\\\".",
|
|
226
|
+
"tags": [
|
|
227
|
+
"motion",
|
|
228
|
+
"animation",
|
|
229
|
+
"glossary",
|
|
230
|
+
"terminology",
|
|
231
|
+
"naming"
|
|
232
|
+
],
|
|
233
|
+
"recommends": [
|
|
234
|
+
"animate",
|
|
235
|
+
"apple-design"
|
|
236
|
+
],
|
|
237
|
+
"profiles": [
|
|
238
|
+
"full"
|
|
239
|
+
]
|
|
240
|
+
},
|
|
185
241
|
{
|
|
186
242
|
"id": "api-connector-builder",
|
|
187
243
|
"description": "Use when writing a client for someone else's REST or GraphQL API: auth flow choice and token refresh, pagination to exhaustion, retry-with-jitter on transient failures only, rate-limit-aware throttling. NOT inbound callbacks (that is `webhooks`), NOT chaining services (that is `automation-flows`), NOT designing your own API (that is `api-design`).",
|
|
@@ -233,6 +289,25 @@
|
|
|
233
289
|
],
|
|
234
290
|
"profiles": []
|
|
235
291
|
},
|
|
292
|
+
{
|
|
293
|
+
"id": "apple-design",
|
|
294
|
+
"description": "Apple's fluid-interface craft on the web: spring damping and response, velocity handoff, momentum projection on a flick, rubber-banding at a boundary, interruptible motion the user can grab mid-flight, translucent materials and backdrop blur, letter-spacing and leading by size. Use for iOS-grade feel, sheets and drag.",
|
|
295
|
+
"tags": [
|
|
296
|
+
"design",
|
|
297
|
+
"motion",
|
|
298
|
+
"springs",
|
|
299
|
+
"gestures",
|
|
300
|
+
"apple"
|
|
301
|
+
],
|
|
302
|
+
"recommends": [
|
|
303
|
+
"animate",
|
|
304
|
+
"design",
|
|
305
|
+
"swift-ios"
|
|
306
|
+
],
|
|
307
|
+
"profiles": [
|
|
308
|
+
"full"
|
|
309
|
+
]
|
|
310
|
+
},
|
|
236
311
|
{
|
|
237
312
|
"id": "article-writing",
|
|
238
313
|
"description": "Use when writing one long-form article end to end — answer-first lede, question-shaped headings, plus its on-page surface (title, meta, slug, FAQ, Article/FAQPage JSON-LD) — or fixing a draft that buries the answer or reads AI-padded. NOT keyword research or topic selection (that is `seo-geo`), NOT the editorial calendar (that is `content-engine`).",
|
|
@@ -256,6 +331,25 @@
|
|
|
256
331
|
],
|
|
257
332
|
"profiles": []
|
|
258
333
|
},
|
|
334
|
+
{
|
|
335
|
+
"id": "ask-sonner",
|
|
336
|
+
"description": "Sonner, the React toast library: mounting Toaster once, toast() calls, promise and loading toasts, updating, dismissing, styling, theming, dark mode, positioning. Use when toasts do not appear, appear twice, sit behind a modal, ignore Tailwind classes, or do nothing from a server action.",
|
|
337
|
+
"tags": [
|
|
338
|
+
"sonner",
|
|
339
|
+
"toasts",
|
|
340
|
+
"notifications",
|
|
341
|
+
"react",
|
|
342
|
+
"library"
|
|
343
|
+
],
|
|
344
|
+
"recommends": [
|
|
345
|
+
"react",
|
|
346
|
+
"nextjs",
|
|
347
|
+
"pick-ui-library"
|
|
348
|
+
],
|
|
349
|
+
"profiles": [
|
|
350
|
+
"full"
|
|
351
|
+
]
|
|
352
|
+
},
|
|
259
353
|
{
|
|
260
354
|
"id": "astro",
|
|
261
355
|
"description": "Use when building a content-driven or marketing site with Astro 6: static-first pages, islands and partial hydration, content collections, server islands, per-route on-demand rendering, deploy adapters, and Astro 5→6 migration. NOT app-router React with server actions and heavy client interactivity (that is `nextjs`).",
|
|
@@ -1315,6 +1409,27 @@
|
|
|
1315
1409
|
],
|
|
1316
1410
|
"profiles": []
|
|
1317
1411
|
},
|
|
1412
|
+
{
|
|
1413
|
+
"id": "design-eng",
|
|
1414
|
+
"description": "Umbrella for frontend craft: routes a UI request to the sibling that owns it — build motion, review it, audit it, find where it is missing, name an effect, gesture physics, prototype variants, pick a library. Use when an app works but feels cheap or unpolished, or when a frontend request could belong to several of them.",
|
|
1415
|
+
"tags": [
|
|
1416
|
+
"design",
|
|
1417
|
+
"frontend",
|
|
1418
|
+
"ui",
|
|
1419
|
+
"routing",
|
|
1420
|
+
"craft"
|
|
1421
|
+
],
|
|
1422
|
+
"recommends": [
|
|
1423
|
+
"animate",
|
|
1424
|
+
"review-animations",
|
|
1425
|
+
"apple-design",
|
|
1426
|
+
"design"
|
|
1427
|
+
],
|
|
1428
|
+
"profiles": [
|
|
1429
|
+
"core",
|
|
1430
|
+
"full"
|
|
1431
|
+
]
|
|
1432
|
+
},
|
|
1318
1433
|
{
|
|
1319
1434
|
"id": "digitalocean",
|
|
1320
1435
|
"description": "Use when deploying or operating a workload on DigitalOcean — Droplet vs App Platform vs Functions, doctl, app spec YAML, Managed Postgres/MySQL/Valkey on the VPC, S3-compatible Spaces + CDN. NOT host-agnostic CI/CD or rollback strategy (that is `deployment`), NOT a bare Hetzner VPS (that is `hetzner`), NOT another managed PaaS (that is `railway`).",
|
|
@@ -1790,6 +1905,24 @@
|
|
|
1790
1905
|
],
|
|
1791
1906
|
"profiles": []
|
|
1792
1907
|
},
|
|
1908
|
+
{
|
|
1909
|
+
"id": "find-animation-opportunities",
|
|
1910
|
+
"description": "Sweep a UI for what does not animate but should, and reject what should not — each suggestion with an exact curve and duration, plus the rejected candidates. Read-only. Use for 'what could be animated here', 'where would motion help', or an interface that feels static and dead.",
|
|
1911
|
+
"tags": [
|
|
1912
|
+
"motion",
|
|
1913
|
+
"animation",
|
|
1914
|
+
"restraint",
|
|
1915
|
+
"opportunities",
|
|
1916
|
+
"ui"
|
|
1917
|
+
],
|
|
1918
|
+
"recommends": [
|
|
1919
|
+
"animate",
|
|
1920
|
+
"improve-animations"
|
|
1921
|
+
],
|
|
1922
|
+
"profiles": [
|
|
1923
|
+
"full"
|
|
1924
|
+
]
|
|
1925
|
+
},
|
|
1793
1926
|
{
|
|
1794
1927
|
"id": "finetuning",
|
|
1795
1928
|
"description": "Use when adapting an open-weight model to a target form or behavior — tone, output format, reasoning pattern — via LoRA/QLoRA or full fine-tuning with TRL SFTTrainer, then preference optimization (DPO/ORPO/KTO/GRPO), and for fine-tune vs prompt vs RAG. NOT adding facts to a model (that is rag); NOT the single-GPU Unsloth backend or GGUF export (that is unsloth).",
|
|
@@ -2383,6 +2516,25 @@
|
|
|
2383
2516
|
"full"
|
|
2384
2517
|
]
|
|
2385
2518
|
},
|
|
2519
|
+
{
|
|
2520
|
+
"id": "improve-animations",
|
|
2521
|
+
"description": "Audit a whole codebase's animation and motion, then write prioritized findings and self-contained plans another agent can execute. Read-only. Use for 'improve the animations', 'make the app feel better', or a roadmap of motion fixes — rather than a verdict on one diff.",
|
|
2522
|
+
"tags": [
|
|
2523
|
+
"motion",
|
|
2524
|
+
"animation",
|
|
2525
|
+
"audit",
|
|
2526
|
+
"plan",
|
|
2527
|
+
"codebase"
|
|
2528
|
+
],
|
|
2529
|
+
"recommends": [
|
|
2530
|
+
"review-animations",
|
|
2531
|
+
"animate",
|
|
2532
|
+
"plan"
|
|
2533
|
+
],
|
|
2534
|
+
"profiles": [
|
|
2535
|
+
"full"
|
|
2536
|
+
]
|
|
2537
|
+
},
|
|
2386
2538
|
{
|
|
2387
2539
|
"id": "init",
|
|
2388
2540
|
"description": "Use when starting from nothing or pointing rsc at an existing project — the front door. Gauges technical level and the accompaniment dial first (non-technical by default), discovers what the user wants to build or govern (any stack, or a non-code harness: company/ops, research, knowledge, content), writes the profile to 02-DOCS, and installs the skills discovery justified. NOT the scaffolder (that is `harness`), NOT a stack skill.",
|
|
@@ -3458,6 +3610,25 @@
|
|
|
3458
3610
|
],
|
|
3459
3611
|
"profiles": []
|
|
3460
3612
|
},
|
|
3613
|
+
{
|
|
3614
|
+
"id": "pick-ui-library",
|
|
3615
|
+
"description": "Pick the frontend library for a task from a curated list: dialogs and popovers, command palette, toasts, one-time-password input, charts, virtualization, drag and drop, state, conditional classNames, variants, dark mode. Use instead of hand-rolling a component or installing an abandoned package.",
|
|
3616
|
+
"tags": [
|
|
3617
|
+
"frontend",
|
|
3618
|
+
"libraries",
|
|
3619
|
+
"dependencies",
|
|
3620
|
+
"react",
|
|
3621
|
+
"ui"
|
|
3622
|
+
],
|
|
3623
|
+
"recommends": [
|
|
3624
|
+
"react",
|
|
3625
|
+
"nextjs",
|
|
3626
|
+
"animate"
|
|
3627
|
+
],
|
|
3628
|
+
"profiles": [
|
|
3629
|
+
"full"
|
|
3630
|
+
]
|
|
3631
|
+
},
|
|
3461
3632
|
{
|
|
3462
3633
|
"id": "pitch-deck",
|
|
3463
3634
|
"description": "Use when building or fixing an investor fundraising deck — the narrative arc, the slide-by-slide story, and the few numbers that actually move an investment decision, for a pre-seed, seed or Series A raise (or an accelerator application deck). Decides what goes on each slide, in what order, with which metric, sequenced the way an investor evaluates risk. NOT rendering, theming or exporting the slides into a designed PDF or PPTX (that is `presentations`), NOT the projection spreadsheet behind the numbers (that is `financial-model`).",
|
|
@@ -3732,6 +3903,25 @@
|
|
|
3732
3903
|
],
|
|
3733
3904
|
"profiles": []
|
|
3734
3905
|
},
|
|
3906
|
+
{
|
|
3907
|
+
"id": "prototype",
|
|
3908
|
+
"description": "Build several genuinely different versions — variants, takes, options, directions — of one UI piece behind a visual picker, so you flip through them live and promote the winner. Use to explore a look before committing, or when you do not yet know what you want something to look like.",
|
|
3909
|
+
"tags": [
|
|
3910
|
+
"design",
|
|
3911
|
+
"variants",
|
|
3912
|
+
"exploration",
|
|
3913
|
+
"picker",
|
|
3914
|
+
"ui"
|
|
3915
|
+
],
|
|
3916
|
+
"recommends": [
|
|
3917
|
+
"design",
|
|
3918
|
+
"animate",
|
|
3919
|
+
"nextjs"
|
|
3920
|
+
],
|
|
3921
|
+
"profiles": [
|
|
3922
|
+
"full"
|
|
3923
|
+
]
|
|
3924
|
+
},
|
|
3735
3925
|
{
|
|
3736
3926
|
"id": "python",
|
|
3737
3927
|
"description": "Use when the task is Python itself, in any framework or none: PEP 695 generics, mypy --strict typing, dataclass/Protocol/TypedDict/Enum choices, asyncio.TaskGroup, stdlib idioms, src/ layout + pyproject.toml with uv, ruff+mypy+pytest gate. NOT a FastAPI/ASGI service (that is fastapi), NOT a deep pytest suite (that is testing-py).",
|
|
@@ -4060,6 +4250,25 @@
|
|
|
4060
4250
|
"full"
|
|
4061
4251
|
]
|
|
4062
4252
|
},
|
|
4253
|
+
{
|
|
4254
|
+
"id": "review-animations",
|
|
4255
|
+
"description": "Review, critique or grade existing animation and motion code against a strict craft bar — easing, duration, transform-origin, interruptibility, GPU-only properties, reduced motion, enter/exit asymmetry, stagger. Default is to flag; approval is earned. Use on the transitions in a diff or a component.",
|
|
4256
|
+
"tags": [
|
|
4257
|
+
"motion",
|
|
4258
|
+
"animation",
|
|
4259
|
+
"review",
|
|
4260
|
+
"craft",
|
|
4261
|
+
"ui"
|
|
4262
|
+
],
|
|
4263
|
+
"recommends": [
|
|
4264
|
+
"animate",
|
|
4265
|
+
"improve-animations",
|
|
4266
|
+
"code-review"
|
|
4267
|
+
],
|
|
4268
|
+
"profiles": [
|
|
4269
|
+
"full"
|
|
4270
|
+
]
|
|
4271
|
+
},
|
|
4063
4272
|
{
|
|
4064
4273
|
"id": "review-management",
|
|
4065
4274
|
"description": "Use when a public review needs an on-voice reply, when you need to earn more reviews legally, or when an aggregate rating is slipping across Google Business Profile, Trustpilot, the App Store or Google Play — including deciding reply versus flag, getting an unfair one-star removed rather than merely answered, and wiring programmatic replies. NOT a private support ticket against an SLA (that is `customer-support`), NOT churn, NPS or save plays (that is `retention`).",
|
|
@@ -5370,6 +5579,25 @@
|
|
|
5370
5579
|
"full"
|
|
5371
5580
|
]
|
|
5372
5581
|
},
|
|
5582
|
+
{
|
|
5583
|
+
"id": "write-swift",
|
|
5584
|
+
"description": "Modern Swift at the language level: structs and value types versus classes, Swift 6 data-race safety, actors, async/await and task groups, `some` versus `any`, ARC and retain cycles, Swift Testing, macros. Use for a deadlock, a hang, a data race, a concurrency error, or migrating to Swift 6.",
|
|
5585
|
+
"tags": [
|
|
5586
|
+
"swift",
|
|
5587
|
+
"language",
|
|
5588
|
+
"concurrency",
|
|
5589
|
+
"generics",
|
|
5590
|
+
"testing"
|
|
5591
|
+
],
|
|
5592
|
+
"recommends": [
|
|
5593
|
+
"swift-ios",
|
|
5594
|
+
"apple-design",
|
|
5595
|
+
"testing-web"
|
|
5596
|
+
],
|
|
5597
|
+
"profiles": [
|
|
5598
|
+
"full"
|
|
5599
|
+
]
|
|
5600
|
+
},
|
|
5373
5601
|
{
|
|
5374
5602
|
"id": "youtube-api",
|
|
5375
5603
|
"description": "Use when wiring code to a real YouTube channel: user OAuth 2.0, resumable videos.insert uploads, editing metadata after publish, pulling views/watch time/retention/traffic from the Analytics API v2 into a dated 02-DOCS/wiki/youtube/ feedback log. NOT what to publish or how to title and thumbnail it (that is youtube-strategy / youtube-packaging).",
|
package/package.json
CHANGED
package/scripts/detect-repo.js
CHANGED
|
@@ -1,13 +1,39 @@
|
|
|
1
1
|
import { existsSync, readFileSync, readdirSync } from 'node:fs';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
|
|
4
|
+
// What counts as a frontend, and which stack skill owns it. Before this table, "frontend" meant
|
|
5
|
+
// React or Next and nothing else, so a Vue/Svelte/Astro/Angular/Solid repo got no design skill at
|
|
6
|
+
// all — even though the catalog ships a skill for each of them. Every entry here also earns the
|
|
7
|
+
// `design-eng` umbrella, which is the one skill that routes a UI request to the sibling that owns
|
|
8
|
+
// it. Kept as a table, not a chain of `if`s, so adding a framework is one line and the test
|
|
9
|
+
// iterates it. Spec: 02-DOCS/wiki/sdd/specs/motion-craft-skills.md
|
|
10
|
+
const FRONTEND_DEPS = [
|
|
11
|
+
['next', 'nextjs'],
|
|
12
|
+
['react', 'nextjs'],
|
|
13
|
+
['vue', 'vue-nuxt'],
|
|
14
|
+
['nuxt', 'vue-nuxt'],
|
|
15
|
+
['svelte', 'svelte'],
|
|
16
|
+
['@sveltejs/kit', 'svelte'],
|
|
17
|
+
['astro', 'astro'],
|
|
18
|
+
['@angular/core', 'angular'],
|
|
19
|
+
['solid-js', 'solid-js'],
|
|
20
|
+
];
|
|
21
|
+
|
|
4
22
|
export function detectRepo(dir = process.cwd()) {
|
|
5
23
|
const found = new Set();
|
|
6
24
|
const has = (f) => existsSync(join(dir, f));
|
|
7
25
|
const pkg = has('package.json') ? safeJson(join(dir, 'package.json')) : null;
|
|
8
26
|
if (pkg) {
|
|
9
27
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
10
|
-
|
|
28
|
+
for (const [dep, stack] of FRONTEND_DEPS) {
|
|
29
|
+
if (!deps[dep]) continue;
|
|
30
|
+
found.add(stack);
|
|
31
|
+
found.add('design');
|
|
32
|
+
// The umbrella, not a motion skill: it decides which of the craft siblings answers. A repo
|
|
33
|
+
// that never animates anything still benefits from the routing, and one that does gets sent
|
|
34
|
+
// to the right place instead of having `design` guess.
|
|
35
|
+
found.add('design-eng');
|
|
36
|
+
}
|
|
11
37
|
}
|
|
12
38
|
if (has('pubspec.yaml')) { found.add('flutter'); found.add('design'); }
|
|
13
39
|
if (has('requirements.txt') || has('pyproject.toml')) found.add('fastapi');
|
package/scripts/drift-check.js
CHANGED
|
@@ -146,18 +146,50 @@ export function basesFor(docPath, { mode, root }) {
|
|
|
146
146
|
return [dirname(docPath), root, join(root, '02-DOCS'), join(root, '02-DOCS', 'wiki'), join(root, 'skills')];
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
-
|
|
149
|
+
// `existsSync` asks the filesystem, and on APFS/HFS+ (macOS) and NTFS (Windows) the filesystem
|
|
150
|
+
// ignores case. So a link to `AUDIT.md` resolves against a file named `audit.md` and this gate goes
|
|
151
|
+
// GREEN on the maintainer's machine while Linux CI — and every installed user — sees a broken link.
|
|
152
|
+
// That is P2 in its most expensive form: the gate fails open exactly where the work is done. It
|
|
153
|
+
// happened for real (the motion-craft port moved references and one link kept its old casing).
|
|
154
|
+
//
|
|
155
|
+
// So existence is checked one path segment at a time against the parent's actual directory listing,
|
|
156
|
+
// which is byte-exact on every filesystem. The walk starts at `root`, which is real by
|
|
157
|
+
// construction; the declared hole is a target that resolves OUTSIDE the repo, where there is no
|
|
158
|
+
// listing we can trust — the repo's own path may sit under a differently-cased volume or behind a
|
|
159
|
+
// symlink, and a false positive in a blocking gate costs more than a named gap.
|
|
160
|
+
// Spec: 02-DOCS/wiki/sdd/specs/drift-check-case.md
|
|
161
|
+
function existsExact(absTarget, root, cache) {
|
|
162
|
+
const rel = relative(root, absTarget);
|
|
163
|
+
// Outside the repo (or the root itself): keep the old behaviour, and say so rather than guess.
|
|
164
|
+
if (rel === '' || rel.startsWith('..') || rel.startsWith('/')) return existsSync(absTarget);
|
|
165
|
+
|
|
166
|
+
let dir = root;
|
|
167
|
+
for (const segment of rel.split('/')) {
|
|
168
|
+
let entries = cache.get(dir);
|
|
169
|
+
if (entries === undefined) {
|
|
170
|
+
// An unreadable directory is not evidence of drift; fall back rather than accuse.
|
|
171
|
+
try { entries = new Set(readdirSync(dir)); } catch { return existsSync(absTarget); }
|
|
172
|
+
cache.set(dir, entries);
|
|
173
|
+
}
|
|
174
|
+
if (!entries.has(segment)) return false;
|
|
175
|
+
dir = join(dir, segment);
|
|
176
|
+
}
|
|
177
|
+
return true;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const resolves = (target, bases, root, cache) =>
|
|
181
|
+
bases.some((b) => existsExact(resolve(b, target), root, cache));
|
|
150
182
|
|
|
151
183
|
// Knowledge mode only. The authoring standards write per-skill paths generically — "every skill
|
|
152
184
|
// carries `evals/cases.yaml`" — which is a claim about a shape shared by 258 directories, not a
|
|
153
185
|
// location. Resolving it against any one skill is the honest reading; treating it as drift
|
|
154
186
|
// produced five findings that were never wrong.
|
|
155
|
-
function resolvesInAnySkill(target, root) {
|
|
187
|
+
function resolvesInAnySkill(target, root, cache) {
|
|
156
188
|
if (target.startsWith('.') || target.startsWith('/')) return false;
|
|
157
189
|
const skillsDir = join(root, 'skills');
|
|
158
190
|
if (!existsSync(skillsDir)) return false;
|
|
159
191
|
for (const e of readdirSync(skillsDir, { withFileTypes: true })) {
|
|
160
|
-
if (e.isDirectory() &&
|
|
192
|
+
if (e.isDirectory() && existsExact(join(skillsDir, e.name, target), root, cache)) return true;
|
|
161
193
|
}
|
|
162
194
|
return false;
|
|
163
195
|
}
|
|
@@ -186,6 +218,9 @@ export function scanTree(dir, { mode, root = REPO, label = null } = {}) {
|
|
|
186
218
|
const findings = [];
|
|
187
219
|
let claims = 0;
|
|
188
220
|
let skipped = 0;
|
|
221
|
+
// Directory listings, memoized per scan rather than per module: 824 claims share a few hundred
|
|
222
|
+
// directories, and a cache that outlived the scan would answer from a stale listing.
|
|
223
|
+
const cache = new Map();
|
|
189
224
|
for (const doc of markdownFiles(dir)) {
|
|
190
225
|
const text = readFileSync(doc, 'utf8');
|
|
191
226
|
const raw = mode === 'catalog'
|
|
@@ -199,8 +234,8 @@ export function scanTree(dir, { mode, root = REPO, label = null } = {}) {
|
|
|
199
234
|
continue;
|
|
200
235
|
}
|
|
201
236
|
claims++;
|
|
202
|
-
if (mode === 'knowledge' && resolvesInAnySkill(c.target, root)) continue;
|
|
203
|
-
if (!resolves(c.target, bases)) {
|
|
237
|
+
if (mode === 'knowledge' && resolvesInAnySkill(c.target, root, cache)) continue;
|
|
238
|
+
if (!resolves(c.target, bases, root, cache)) {
|
|
204
239
|
findings.push({
|
|
205
240
|
doc: relative(root, doc),
|
|
206
241
|
line: c.line,
|
package/scripts/lib/domains.js
CHANGED
|
@@ -17,13 +17,14 @@ export const DOMAINS = [
|
|
|
17
17
|
{ title: 'AI — build it in', ids: ['building-agents', 'rag', 'embeddings-search', 'prompt-engineering', 'llm-pipeline', 'agent-eval', 'chatbot', 'ai-media', 'replicate-images', 'structured-extraction', 'agent-safety', 'cost-tracking'] },
|
|
18
18
|
{ title: 'AI — run it on', ids: ['replicate', 'runpod', 'modal', 'huggingface', 'ollama', 'together-fireworks', 'fal'] },
|
|
19
19
|
{ title: 'AI — train it', ids: ['machine-learning', 'deep-learning', 'nlp', 'finetuning', 'training-data', 'unsloth', 'open-weights', 'vllm'] },
|
|
20
|
-
{ title: 'Languages', ids: ['typescript', 'python', 'java', 'csharp-dotnet', 'php', 'ruby', 'cpp', 'elixir', 'bash-scripting', 'sql', 'go'] },
|
|
21
|
-
{ title: 'Frameworks & app stacks', ids: ['fastapi', 'nextjs', 'react', 'react-native', 'vue-nuxt', 'angular', 'svelte', 'astro', 'solid-js', 'htmx', 'nodejs', 'nestjs', 'django', 'laravel', 'rails', 'spring-boot', 'phoenix', 'flutter', 'swift-ios', 'kotlin-android', 'compose-multiplatform', 'expo', 'tauri', 'electron', 'rust', 'wordpress', 'shopify', 'no-code-app', 'chrome-extension', 'api-design'] },
|
|
20
|
+
{ title: 'Languages', ids: ['typescript', 'python', 'java', 'csharp-dotnet', 'php', 'ruby', 'cpp', 'elixir', 'bash-scripting', 'sql', 'go', 'write-swift'] },
|
|
21
|
+
{ title: 'Frameworks & app stacks', ids: ['fastapi', 'nextjs', 'react', 'react-native', 'vue-nuxt', 'angular', 'svelte', 'astro', 'solid-js', 'htmx', 'nodejs', 'nestjs', 'django', 'laravel', 'rails', 'spring-boot', 'phoenix', 'flutter', 'swift-ios', 'kotlin-android', 'compose-multiplatform', 'expo', 'tauri', 'electron', 'rust', 'wordpress', 'shopify', 'no-code-app', 'chrome-extension', 'api-design', 'pick-ui-library', 'ask-sonner'] },
|
|
22
22
|
{ title: 'Game development', ids: ['godot', 'unity', 'unreal', 'game-design', 'game-storytelling', 'level-design', 'gamedev-shaders', 'gamedev-multiplayer', 'gamedev-physics', 'gamedev-pathing', 'gamedev-shipping'] },
|
|
23
23
|
{ title: 'Databases & data layer', ids: ['postgresdb', 'mysql', 'mongodb', 'redis', 'supabase', 'neon', 'planetscale', 'sqlite-turso', 'prisma-orm', 'drizzle-orm', 'firebase', 'dynamodb', 'vector-db', 'clickhouse-analytics', 'duckdb', 'db-migrations', 'backups'] },
|
|
24
24
|
{ title: 'Ship & operate — platforms', ids: ['vercel', 'netlify', 'cloudflare', 'railway', 'render', 'fly-io', 'coolify', 'hetzner', 'digitalocean', 'aws-essentials', 'gcp-essentials'] },
|
|
25
25
|
{ title: 'Ship & operate — devops', ids: ['docker', 'github-actions', 'git-workflow', 'domains-dns', 'monitoring', 'email-deliverability', 'scaling', 'deployment', 'deprecation'] },
|
|
26
26
|
{ title: 'Ship & operate — quality & security', ids: ['code-review', 'security-scan', 'secure-coding', 'testing-py', 'testing-web', 'testing-go', 'e2e-testing', 'accessibility', 'performance', 'error-handling', 'observability'] },
|
|
27
|
+
{ title: 'Motion & interface craft', ids: ['design-eng', 'animate', 'animate-expo', 'review-animations', 'improve-animations', 'find-animation-opportunities', 'animation-vocabulary', 'apple-design', 'prototype'] },
|
|
27
28
|
{ title: 'Design & content craft', ids: ['design', 'presentations', 'course-storytelling', 'course-builder', 'technical-writing', 'translation-l10n'] },
|
|
28
29
|
{ title: 'Knowledge & meta', ids: ['knowledge-ops', 'codebase-onboarding', 'research-ops', 'decision-records', 'continuous-learning', 'skill-scout', 'context-budget', 'roast-me', 'fable-operator'] },
|
|
29
30
|
];
|