@ericrisco/rsc 1.1.4 → 1.1.6
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 +81 -11
- package/manifest.json +56 -231
- package/package.json +1 -1
- package/scripts/doctor.js +68 -1
- package/scripts/install-apply.js +91 -16
- package/scripts/lib/divergence.js +33 -0
- package/scripts/lib/domains.js +3 -3
- package/scripts/lib/manifest-file.js +53 -0
- package/scripts/lib/repair.js +156 -0
- package/scripts/lib/ui.js +5 -0
- package/scripts/rsc.js +84 -11
- package/skills/design/SKILL.md +3 -3
- package/skills/design/references/design-systems.md +1 -1
- package/skills/design/references/inspiration-sources.md +2 -2
- package/skills/design/references/motion-and-interaction.md +2 -2
- package/skills/design-dna/evals/cases.yaml +1 -1
- package/skills/design-loop/SKILL.md +3 -3
- package/skills/design-loop/evals/cases.yaml +3 -3
- package/skills/expo/SKILL.md +1 -1
- package/skills/motion-craft/SKILL.md +125 -0
- package/skills/motion-craft/evals/cases.yaml +38 -0
- package/skills/motion-craft/scripts/verify.sh +75 -0
- package/skills/react/SKILL.md +2 -2
- package/skills/react-native/SKILL.md +1 -1
- package/skills/suggest/SKILL.md +25 -1
- package/skills/swift-ios/SKILL.md +2 -2
- package/skills/ui-engineering/SKILL.md +114 -0
- package/skills/ui-engineering/evals/cases.yaml +38 -0
- package/skills/variant-explorer/SKILL.md +93 -0
- package/skills/variant-explorer/evals/cases.yaml +38 -0
- package/targets/_md-block.js +17 -4
- package/targets/claude.js +17 -7
- package/targets/index.js +66 -19
- package/skills/animate/SKILL.md +0 -851
- package/skills/animate/evals/cases.yaml +0 -36
- package/skills/animate/references/recipes.md +0 -324
- package/skills/animate-expo/SKILL.md +0 -281
- package/skills/animate-expo/evals/cases.yaml +0 -36
- package/skills/animate-expo/references/recipes.md +0 -385
- package/skills/animation-vocabulary/SKILL.md +0 -189
- package/skills/animation-vocabulary/evals/cases.yaml +0 -31
- package/skills/apple-design/SKILL.md +0 -301
- package/skills/apple-design/evals/cases.yaml +0 -33
- package/skills/ask-sonner/SKILL.md +0 -104
- package/skills/ask-sonner/evals/cases.yaml +0 -33
- package/skills/ask-sonner/references/api.md +0 -64
- package/skills/design-eng/SKILL.md +0 -88
- package/skills/design-eng/evals/cases.yaml +0 -36
- package/skills/find-animation-opportunities/SKILL.md +0 -150
- package/skills/find-animation-opportunities/evals/cases.yaml +0 -31
- package/skills/improve-animations/SKILL.md +0 -126
- package/skills/improve-animations/evals/cases.yaml +0 -31
- package/skills/improve-animations/references/audit.md +0 -115
- package/skills/improve-animations/references/plan-template.md +0 -73
- package/skills/pick-ui-library/SKILL.md +0 -101
- package/skills/pick-ui-library/evals/cases.yaml +0 -33
- package/skills/pick-ui-library/references/component-galleries.md +0 -59
- package/skills/prototype/SKILL.md +0 -113
- package/skills/prototype/evals/cases.yaml +0 -31
- package/skills/prototype/references/picker.md +0 -197
- package/skills/review-animations/SKILL.md +0 -188
- package/skills/review-animations/evals/cases.yaml +0 -34
- package/skills/review-animations/references/standards.md +0 -187
- package/skills/review-animations/scripts/verify.sh +0 -164
- package/skills/write-swift/SKILL.md +0 -413
- package/skills/write-swift/evals/cases.yaml +0 -36
package/README.md
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
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 (272 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` — 272 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)
|
|
9
|
-
[](#the-catalog)
|
|
10
10
|
[](LICENSE)
|
|
11
11
|
[](https://github.com/ericrisco/rsc-harness/stargazers)
|
|
12
12
|
|
|
@@ -17,7 +17,7 @@ skills that fit — one at a time — into every assistant you pick, and keeps t
|
|
|
17
17
|
equipped as you work.
|
|
18
18
|
|
|
19
19
|
From *"document my company"* to *"ship a FastAPI service"* to *"grow my YouTube
|
|
20
|
-
channel"* — **
|
|
20
|
+
channel"* — **272 skills across 23 domains**, every one researched against live
|
|
21
21
|
2025-2026 sources and **adversarially scored ≥ 8.5/10** before it shipped.
|
|
22
22
|
|
|
23
23
|
```bash
|
|
@@ -26,7 +26,7 @@ npx @ericrisco/rsc # plain-language wizard — no jargon, installs wh
|
|
|
26
26
|
|
|
27
27
|
<br>
|
|
28
28
|
|
|
29
|
-
<img src="https://raw.githubusercontent.com/ericrisco/rsc-harness/main/site/meta-harness.png" alt="rsc — the model (Claude, GPT, Gemini) is the brain your coding agent rents, and you already have that. Claude Code, Codex and opencode sit in the middle. Below them the rsc meta-harness adds everything the model lacks: memory (02-DOCS/) so it stops inventing, arms (01-TOOLS/) so it can execute, a trade (
|
|
29
|
+
<img src="https://raw.githubusercontent.com/ericrisco/rsc-harness/main/site/meta-harness.png" alt="rsc — the model (Claude, GPT, Gemini) is the brain your coding agent rents, and you already have that. Claude Code, Codex and opencode sit in the middle. Below them the rsc meta-harness adds everything the model lacks: memory (02-DOCS/) so it stops inventing, arms (01-TOOLS/) so it can execute, a trade (272 skills) so it stops guessing, and reflexes (deterministic hooks) so it cannot forget the rule mid-session." width="960">
|
|
30
30
|
|
|
31
31
|
**The model is the only part your agent already has.** `rsc` is the meta-harness that adds
|
|
32
32
|
the rest: a **memory** so it stops inventing, **arms** so it can execute, a **trade** so it stops
|
|
@@ -52,6 +52,7 @@ user wants**, reads the repo, then installs the floor (`orient` + `rsc-suggest`
|
|
|
52
52
|
`init`) plus only the skills that fit — one at a time. No global install and no API key needed.
|
|
53
53
|
|
|
54
54
|
- **Choose assistants non-interactively:** `npx @ericrisco/rsc@latest --target claude` (comma-separate for several).
|
|
55
|
+
- **Two assistants already installed?** rsc asks instead of guessing. `--target` settles it in one word.
|
|
55
56
|
- **Already installed, just refreshing skills + hooks:** `rsc sync` (or re-run the command above).
|
|
56
57
|
- **Add one skill by id:** `rsc add <id>` · **browse the catalog:** `rsc consult "<what you want>"` or `rsc list`.
|
|
57
58
|
|
|
@@ -139,7 +140,7 @@ $ rsc
|
|
|
139
140
|
██████╗ ███████╗ ██████╗ ← animated gradient wordmark
|
|
140
141
|
██╔══██╗██╔════╝██╔════╝
|
|
141
142
|
██████╔╝███████╗██║
|
|
142
|
-
|
|
143
|
+
272 skills · one CLI · zero bloat
|
|
143
144
|
|
|
144
145
|
What do you want to do? ↑↓ move · enter select
|
|
145
146
|
❯ Base install — the essentials (8 skills)
|
|
@@ -187,7 +188,7 @@ rsc add youtube-api remotion-video # …grow a channel, edit with Remotion
|
|
|
187
188
|
rsc add fastapi --target claude,codex # install into several assistants at once
|
|
188
189
|
rsc install --profile minimal # the base: orient + suggest + bro + unslop + show-me + eli5 + harness + init
|
|
189
190
|
rsc install --profile core # floor + the full SDD workflow
|
|
190
|
-
rsc install --profile full # everything (all
|
|
191
|
+
rsc install --profile full # everything (all 272 skills)
|
|
191
192
|
rsc install --profile full --without go
|
|
192
193
|
rsc consult "I want to launch a SaaS" # recommend only, no install
|
|
193
194
|
rsc registry refresh # write .rsc/skill-registry.{json,md}
|
|
@@ -203,6 +204,75 @@ rsc uninstall postgresdb --dry-run # preview a removal
|
|
|
203
204
|
|
|
204
205
|
---
|
|
205
206
|
|
|
207
|
+
|
|
208
|
+
## 👥 Sharing a harness with your team
|
|
209
|
+
|
|
210
|
+
The harness travels by git, but not all of it — and the split is the point.
|
|
211
|
+
|
|
212
|
+
**Commit these:**
|
|
213
|
+
|
|
214
|
+
| | |
|
|
215
|
+
| --- | --- |
|
|
216
|
+
| `.rsc.json` | The decision: which assistants, which skills, **which catalog version**, the developer tier, which gates you disarmed |
|
|
217
|
+
| `01-TOOLS/` · `02-DOCS/` | Your tooling and your wiki, if you use them |
|
|
218
|
+
| Skills and agents you wrote by hand | They are yours. rsc does not claim them, does not count them as drift, and does not touch them |
|
|
219
|
+
|
|
220
|
+
**Do not commit these** — rsc adds them to `.gitignore` for you:
|
|
221
|
+
|
|
222
|
+
| | Why |
|
|
223
|
+
| --- | --- |
|
|
224
|
+
| `.rsc/` | Machine state: hook scripts, seals, logs |
|
|
225
|
+
| The skill entries rsc manages | Symlinks on macOS/Linux, real copies on Windows — two incompatible shapes of one thing |
|
|
226
|
+
|
|
227
|
+
Whoever clones runs **one command** and ends up with the same harness:
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
npx @ericrisco/rsc@latest sync
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
Same skills, same version — `.rsc.json` pins the catalog, so a teammate who clones in three
|
|
234
|
+
months gets what you had, not what shipped since. Upgrading is a deliberate act, never a side
|
|
235
|
+
effect of rebuilding.
|
|
236
|
+
|
|
237
|
+
When someone changes the harness and you `git pull`, `rsc doctor` tells you what no longer
|
|
238
|
+
matches. **Nothing is ever written to your machine by a pull** — you are told, and you decide.
|
|
239
|
+
|
|
240
|
+
**Own skills.** A skill your team wrote lives in the repo and already works for whoever clones,
|
|
241
|
+
with no command at all. Declare it in `.rsc.json` under `ownSkills` and `doctor` will also say
|
|
242
|
+
when someone is missing it — that is all declaring does. rsc never installs, updates or
|
|
243
|
+
overwrites it: its version is the commit.
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
## 🩹 Something's off? One command
|
|
247
|
+
|
|
248
|
+
Recognise any of these? They are all the same fix.
|
|
249
|
+
|
|
250
|
+
| What you see | |
|
|
251
|
+
| --- | --- |
|
|
252
|
+
| `"target": "codex"` when you work in Claude Code | |
|
|
253
|
+
| `This target has no hook injection` and you did not expect that | |
|
|
254
|
+
| Skills appear that you never asked for | |
|
|
255
|
+
| You cloned a repo and your assistant sees no skills at all | |
|
|
256
|
+
| A hook seems to run several times per turn | |
|
|
257
|
+
| Template lines showed up inside your hand-written `AGENTS.md` | |
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
npx @ericrisco/rsc@latest repair
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
Safe in any folder: with no rsc there, it says so and writes nothing. It shows what it
|
|
264
|
+
found before touching anything, keeps a recoverable copy, and running it twice changes
|
|
265
|
+
nothing the second time. Add `--dry-run` to see the whole pass without a single write.
|
|
266
|
+
|
|
267
|
+
**What it fixes on its own** — putting the harness back to what was already declared:
|
|
268
|
+
dangling links from a clone, hooks wired several times, the 0.1 layout no assistant reads.
|
|
269
|
+
|
|
270
|
+
**What it asks about** — anything that changes a decision: moving the harness to another
|
|
271
|
+
assistant, or touching files you already committed.
|
|
272
|
+
|
|
273
|
+
**What it never touches:** skills and agents you wrote by hand. rsc did not install them,
|
|
274
|
+
so rsc does not repair, move or delete them — not even when rebuilding from scratch.
|
|
275
|
+
|
|
206
276
|
## Update
|
|
207
277
|
|
|
208
278
|
`rsc` is an npm package, so updating is two steps — bump the package, then
|
|
@@ -253,7 +323,7 @@ just asks in plain language.
|
|
|
253
323
|
|
|
254
324
|
## The catalog
|
|
255
325
|
|
|
256
|
-
|
|
326
|
+
272 skills, grouped by what you're trying to do. Click any skill to read its
|
|
257
327
|
`SKILL.md`. It fires on its own when a task matches.
|
|
258
328
|
|
|
259
329
|
### 🧭 Core & control plane
|
|
@@ -344,11 +414,11 @@ Train and adapt open models end to end: classic ML, deep learning, NLP, fine-tun
|
|
|
344
414
|
|
|
345
415
|
### 🗣️ Languages
|
|
346
416
|
|
|
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/)
|
|
417
|
+
[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/)
|
|
348
418
|
|
|
349
419
|
### 🏗️ Frameworks & app stacks
|
|
350
420
|
|
|
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/)
|
|
421
|
+
[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/)
|
|
352
422
|
|
|
353
423
|
### 🎮 Game development
|
|
354
424
|
|
|
@@ -374,7 +444,7 @@ Three engines + engine-agnostic disciplines. Every engine skill pins the current
|
|
|
374
444
|
|
|
375
445
|
### 🌀 Motion & interface craft
|
|
376
446
|
|
|
377
|
-
[
|
|
447
|
+
[motion-craft](skills/motion-craft/) · [ui-engineering](skills/ui-engineering/) · [variant-explorer](skills/variant-explorer/)
|
|
378
448
|
|
|
379
449
|
### 🎨 Design & content craft
|
|
380
450
|
|
package/manifest.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.1.
|
|
2
|
+
"version": "1.1.6",
|
|
3
3
|
"counts": {
|
|
4
|
-
"skills":
|
|
4
|
+
"skills": 272
|
|
5
5
|
},
|
|
6
6
|
"skills": [
|
|
7
7
|
{
|
|
@@ -182,62 +182,6 @@
|
|
|
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
|
-
},
|
|
241
185
|
{
|
|
242
186
|
"id": "api-connector-builder",
|
|
243
187
|
"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`).",
|
|
@@ -289,25 +233,6 @@
|
|
|
289
233
|
],
|
|
290
234
|
"profiles": []
|
|
291
235
|
},
|
|
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
|
-
},
|
|
311
236
|
{
|
|
312
237
|
"id": "article-writing",
|
|
313
238
|
"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`).",
|
|
@@ -331,25 +256,6 @@
|
|
|
331
256
|
],
|
|
332
257
|
"profiles": []
|
|
333
258
|
},
|
|
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
|
-
},
|
|
353
259
|
{
|
|
354
260
|
"id": "astro",
|
|
355
261
|
"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`).",
|
|
@@ -1433,28 +1339,6 @@
|
|
|
1433
1339
|
],
|
|
1434
1340
|
"profiles": []
|
|
1435
1341
|
},
|
|
1436
|
-
{
|
|
1437
|
-
"id": "design-eng",
|
|
1438
|
-
"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.",
|
|
1439
|
-
"tags": [
|
|
1440
|
-
"design",
|
|
1441
|
-
"frontend",
|
|
1442
|
-
"ui",
|
|
1443
|
-
"routing",
|
|
1444
|
-
"craft"
|
|
1445
|
-
],
|
|
1446
|
-
"recommends": [
|
|
1447
|
-
"design-loop",
|
|
1448
|
-
"animate",
|
|
1449
|
-
"review-animations",
|
|
1450
|
-
"apple-design",
|
|
1451
|
-
"design"
|
|
1452
|
-
],
|
|
1453
|
-
"profiles": [
|
|
1454
|
-
"core",
|
|
1455
|
-
"full"
|
|
1456
|
-
]
|
|
1457
|
-
},
|
|
1458
1342
|
{
|
|
1459
1343
|
"id": "design-loop",
|
|
1460
1344
|
"description": "Use when something must be built well and there is a real reference it should beat: turn what makes the reference good into measured mechanisms, then run a builder and three fresh-context critics until all three pass. Fires on 'design loop', 'make it as good as <site>', 'it looks generic'. NOT keeping an already-won look (that is `design-dna`).",
|
|
@@ -1972,24 +1856,6 @@
|
|
|
1972
1856
|
],
|
|
1973
1857
|
"profiles": []
|
|
1974
1858
|
},
|
|
1975
|
-
{
|
|
1976
|
-
"id": "find-animation-opportunities",
|
|
1977
|
-
"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.",
|
|
1978
|
-
"tags": [
|
|
1979
|
-
"motion",
|
|
1980
|
-
"animation",
|
|
1981
|
-
"restraint",
|
|
1982
|
-
"opportunities",
|
|
1983
|
-
"ui"
|
|
1984
|
-
],
|
|
1985
|
-
"recommends": [
|
|
1986
|
-
"animate",
|
|
1987
|
-
"improve-animations"
|
|
1988
|
-
],
|
|
1989
|
-
"profiles": [
|
|
1990
|
-
"full"
|
|
1991
|
-
]
|
|
1992
|
-
},
|
|
1993
1859
|
{
|
|
1994
1860
|
"id": "finetuning",
|
|
1995
1861
|
"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).",
|
|
@@ -2583,25 +2449,6 @@
|
|
|
2583
2449
|
"full"
|
|
2584
2450
|
]
|
|
2585
2451
|
},
|
|
2586
|
-
{
|
|
2587
|
-
"id": "improve-animations",
|
|
2588
|
-
"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.",
|
|
2589
|
-
"tags": [
|
|
2590
|
-
"motion",
|
|
2591
|
-
"animation",
|
|
2592
|
-
"audit",
|
|
2593
|
-
"plan",
|
|
2594
|
-
"codebase"
|
|
2595
|
-
],
|
|
2596
|
-
"recommends": [
|
|
2597
|
-
"review-animations",
|
|
2598
|
-
"animate",
|
|
2599
|
-
"plan"
|
|
2600
|
-
],
|
|
2601
|
-
"profiles": [
|
|
2602
|
-
"full"
|
|
2603
|
-
]
|
|
2604
|
-
},
|
|
2605
2452
|
{
|
|
2606
2453
|
"id": "init",
|
|
2607
2454
|
"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.",
|
|
@@ -3276,6 +3123,23 @@
|
|
|
3276
3123
|
],
|
|
3277
3124
|
"profiles": []
|
|
3278
3125
|
},
|
|
3126
|
+
{
|
|
3127
|
+
"id": "motion-craft",
|
|
3128
|
+
"description": "Use when an interface moves and the movement has to feel right — durations and easing, what must never animate, fixing motion that reads sluggish, cheap or janky, and reduced-motion. Web and native. NOT the visual system (that is `design`), NOT the graded critique (that is `design-loop`).",
|
|
3129
|
+
"tags": [
|
|
3130
|
+
"motion",
|
|
3131
|
+
"animation",
|
|
3132
|
+
"interface",
|
|
3133
|
+
"craft",
|
|
3134
|
+
"frontend"
|
|
3135
|
+
],
|
|
3136
|
+
"recommends": [
|
|
3137
|
+
"design"
|
|
3138
|
+
],
|
|
3139
|
+
"profiles": [
|
|
3140
|
+
"full"
|
|
3141
|
+
]
|
|
3142
|
+
},
|
|
3279
3143
|
{
|
|
3280
3144
|
"id": "mysql",
|
|
3281
3145
|
"description": "Use when designing, querying, indexing or operating a MySQL or MariaDB database and engine-specific behaviour matters — schema and type choices, index design, reading EXPLAIN, online schema change, replication and replica lag, locking and InnoDB deadlocks, charset traps, and server config. NOT portable SELECT/JOIN/window-function craft (that is `sql`), NOT PostgreSQL engine behaviour like VACUUM or JSONB (that is `postgresdb`), NOT the PlanetScale/Vitess branch-and-deploy workflow (that is `planetscale`).",
|
|
@@ -3677,25 +3541,6 @@
|
|
|
3677
3541
|
],
|
|
3678
3542
|
"profiles": []
|
|
3679
3543
|
},
|
|
3680
|
-
{
|
|
3681
|
-
"id": "pick-ui-library",
|
|
3682
|
-
"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.",
|
|
3683
|
-
"tags": [
|
|
3684
|
-
"frontend",
|
|
3685
|
-
"libraries",
|
|
3686
|
-
"dependencies",
|
|
3687
|
-
"react",
|
|
3688
|
-
"ui"
|
|
3689
|
-
],
|
|
3690
|
-
"recommends": [
|
|
3691
|
-
"react",
|
|
3692
|
-
"nextjs",
|
|
3693
|
-
"animate"
|
|
3694
|
-
],
|
|
3695
|
-
"profiles": [
|
|
3696
|
-
"full"
|
|
3697
|
-
]
|
|
3698
|
-
},
|
|
3699
3544
|
{
|
|
3700
3545
|
"id": "pitch-deck",
|
|
3701
3546
|
"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`).",
|
|
@@ -3970,25 +3815,6 @@
|
|
|
3970
3815
|
],
|
|
3971
3816
|
"profiles": []
|
|
3972
3817
|
},
|
|
3973
|
-
{
|
|
3974
|
-
"id": "prototype",
|
|
3975
|
-
"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.",
|
|
3976
|
-
"tags": [
|
|
3977
|
-
"design",
|
|
3978
|
-
"variants",
|
|
3979
|
-
"exploration",
|
|
3980
|
-
"picker",
|
|
3981
|
-
"ui"
|
|
3982
|
-
],
|
|
3983
|
-
"recommends": [
|
|
3984
|
-
"design",
|
|
3985
|
-
"animate",
|
|
3986
|
-
"nextjs"
|
|
3987
|
-
],
|
|
3988
|
-
"profiles": [
|
|
3989
|
-
"full"
|
|
3990
|
-
]
|
|
3991
|
-
},
|
|
3992
3818
|
{
|
|
3993
3819
|
"id": "python",
|
|
3994
3820
|
"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).",
|
|
@@ -4317,25 +4143,6 @@
|
|
|
4317
4143
|
"full"
|
|
4318
4144
|
]
|
|
4319
4145
|
},
|
|
4320
|
-
{
|
|
4321
|
-
"id": "review-animations",
|
|
4322
|
-
"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.",
|
|
4323
|
-
"tags": [
|
|
4324
|
-
"motion",
|
|
4325
|
-
"animation",
|
|
4326
|
-
"review",
|
|
4327
|
-
"craft",
|
|
4328
|
-
"ui"
|
|
4329
|
-
],
|
|
4330
|
-
"recommends": [
|
|
4331
|
-
"animate",
|
|
4332
|
-
"improve-animations",
|
|
4333
|
-
"code-review"
|
|
4334
|
-
],
|
|
4335
|
-
"profiles": [
|
|
4336
|
-
"full"
|
|
4337
|
-
]
|
|
4338
|
-
},
|
|
4339
4146
|
{
|
|
4340
4147
|
"id": "review-management",
|
|
4341
4148
|
"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`).",
|
|
@@ -5341,6 +5148,26 @@
|
|
|
5341
5148
|
],
|
|
5342
5149
|
"profiles": []
|
|
5343
5150
|
},
|
|
5151
|
+
{
|
|
5152
|
+
"id": "ui-engineering",
|
|
5153
|
+
"description": "Use when the question is how interface should be BUILT — component boundaries, state that belongs in the URL vs the component, loading/empty/error states, forms, optimistic updates, build vs adopt. NOT the visual system (`design`), NOT framework mechanics (`react`/`nextjs`).",
|
|
5154
|
+
"tags": [
|
|
5155
|
+
"interface",
|
|
5156
|
+
"frontend",
|
|
5157
|
+
"architecture",
|
|
5158
|
+
"components",
|
|
5159
|
+
"state",
|
|
5160
|
+
"craft"
|
|
5161
|
+
],
|
|
5162
|
+
"recommends": [
|
|
5163
|
+
"design",
|
|
5164
|
+
"motion-craft"
|
|
5165
|
+
],
|
|
5166
|
+
"profiles": [
|
|
5167
|
+
"core",
|
|
5168
|
+
"full"
|
|
5169
|
+
]
|
|
5170
|
+
},
|
|
5344
5171
|
{
|
|
5345
5172
|
"id": "unit-economics",
|
|
5346
5173
|
"description": "Use when computing or improving the per-customer economics of a business — CAC, LTV, CAC payback period and contribution margin — judging whether the ratios are healthy against current norms, and naming the one lever that fixes the worst number. Covers a blended CAC that hides a bleeding channel, and a model that shows profit while each customer loses money. NOT the multi-year P&L or scenario projection (that is `financial-model`).",
|
|
@@ -5454,6 +5281,23 @@
|
|
|
5454
5281
|
],
|
|
5455
5282
|
"profiles": []
|
|
5456
5283
|
},
|
|
5284
|
+
{
|
|
5285
|
+
"id": "variant-explorer",
|
|
5286
|
+
"description": "Use when someone wants OPTIONS rather than an answer — 'show me a few versions', picking between approaches by seeing them. Genuinely different candidates, cheap to throw away, trade-off named. NOT the critique that judges one (`design-loop`), NOT the spec (`specify`).",
|
|
5287
|
+
"tags": [
|
|
5288
|
+
"prototyping",
|
|
5289
|
+
"divergence",
|
|
5290
|
+
"options",
|
|
5291
|
+
"exploration",
|
|
5292
|
+
"decision"
|
|
5293
|
+
],
|
|
5294
|
+
"recommends": [
|
|
5295
|
+
"design-loop"
|
|
5296
|
+
],
|
|
5297
|
+
"profiles": [
|
|
5298
|
+
"full"
|
|
5299
|
+
]
|
|
5300
|
+
},
|
|
5457
5301
|
{
|
|
5458
5302
|
"id": "vector-db",
|
|
5459
5303
|
"description": "Use when operating a vector store as a data layer — choosing or migrating between Pinecone, Qdrant, Weaviate and pgvector; designing a collection or index (distance metric, dimensions, HNSW parameters, named vectors); filtering on metadata; hybrid dense-plus-sparse search; and quantization to cut RAM and cost. Covers garbage results, silently ignored filters, low recall, slow queries, and filtered queries returning fewer than k rows. NOT producing, chunking or judging embeddings (that is `embeddings-search`).",
|
|
@@ -5694,25 +5538,6 @@
|
|
|
5694
5538
|
"full"
|
|
5695
5539
|
]
|
|
5696
5540
|
},
|
|
5697
|
-
{
|
|
5698
|
-
"id": "write-swift",
|
|
5699
|
-
"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.",
|
|
5700
|
-
"tags": [
|
|
5701
|
-
"swift",
|
|
5702
|
-
"language",
|
|
5703
|
-
"concurrency",
|
|
5704
|
-
"generics",
|
|
5705
|
-
"testing"
|
|
5706
|
-
],
|
|
5707
|
-
"recommends": [
|
|
5708
|
-
"swift-ios",
|
|
5709
|
-
"apple-design",
|
|
5710
|
-
"testing-web"
|
|
5711
|
-
],
|
|
5712
|
-
"profiles": [
|
|
5713
|
-
"full"
|
|
5714
|
-
]
|
|
5715
|
-
},
|
|
5716
5541
|
{
|
|
5717
5542
|
"id": "youtube-api",
|
|
5718
5543
|
"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/doctor.js
CHANGED
|
@@ -3,6 +3,7 @@ import { join } from 'node:path';
|
|
|
3
3
|
import { homedir } from 'node:os';
|
|
4
4
|
import { targetPaths, TARGET_IDS } from '../targets/index.js';
|
|
5
5
|
import { readState } from './lib/state.js';
|
|
6
|
+
import { divergence } from './lib/divergence.js';
|
|
6
7
|
import { loadManifest } from './lib/manifest.js';
|
|
7
8
|
import { listBackups } from './lib/backups.js';
|
|
8
9
|
import { SDD_GATE_TEXT } from '../targets/hook-once.mjs';
|
|
@@ -40,6 +41,40 @@ function selloStatus(root) {
|
|
|
40
41
|
} catch { return { enabled: false }; }
|
|
41
42
|
}
|
|
42
43
|
|
|
44
|
+
// A wired hook is a promise to run a file. `settings.json` existing only proves the
|
|
45
|
+
// promise was made — and a fresh clone brings that file (committed) without .rsc/
|
|
46
|
+
// (ignored), so every session start fails while the report says all-clear. Read the
|
|
47
|
+
// commands we wired and check the files they name actually exist.
|
|
48
|
+
//
|
|
49
|
+
// Hookless targets get an empty list by construction: their always-on surface is a
|
|
50
|
+
// markdown block with no script behind it, so there is nothing that can go missing.
|
|
51
|
+
export function missingHookScripts({ target, home = homedir(), cwd = process.cwd() } = {}) {
|
|
52
|
+
if (HOOKLESS_TARGETS.has(target)) return [];
|
|
53
|
+
const file = targetPaths(target, home, cwd).hookTarget;
|
|
54
|
+
let settings;
|
|
55
|
+
try { settings = JSON.parse(readFileSync(file, 'utf8')); } catch { return []; }
|
|
56
|
+
const commands = [];
|
|
57
|
+
for (const entries of Object.values(settings?.hooks || {})) {
|
|
58
|
+
if (!Array.isArray(entries)) continue;
|
|
59
|
+
for (const entry of entries) for (const h of entry?.hooks || []) {
|
|
60
|
+
if (typeof h?.command === 'string') commands.push(h.command);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
const seen = new Set();
|
|
64
|
+
// Commands name the project through ${CLAUDE_PROJECT_DIR}, which only the client
|
|
65
|
+
// expands. Resolve it here or every wired script reads as missing and the report
|
|
66
|
+
// calls a healthy install broken — the mirror image of the bug this check fixes.
|
|
67
|
+
const expand = (c) => c.split('${CLAUDE_PROJECT_DIR}').join(cwd);
|
|
68
|
+
for (const raw of commands) {
|
|
69
|
+
const cmd = expand(raw);
|
|
70
|
+
for (const m of cmd.matchAll(/["']?([^"'\s]*[\\/]\.rsc[\\/][^"'\s]+\.mjs)["']?/g)) {
|
|
71
|
+
const script = m[1];
|
|
72
|
+
if (!existsSync(script)) seen.add(script);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return [...seen];
|
|
76
|
+
}
|
|
77
|
+
|
|
43
78
|
export function doctor({ target, home, cwd }) {
|
|
44
79
|
const root = cwd || process.cwd();
|
|
45
80
|
const paths = targetPaths(target, home, cwd);
|
|
@@ -50,7 +85,8 @@ export function doctor({ target, home, cwd }) {
|
|
|
50
85
|
target,
|
|
51
86
|
installed: Object.keys(state.skills),
|
|
52
87
|
missing: [],
|
|
53
|
-
|
|
88
|
+
// Wired means it can actually run, not merely that the file declaring it is there.
|
|
89
|
+
hookWired: existsSync(paths.hookTarget) && missingHookScripts({ target, home, cwd }).length === 0,
|
|
54
90
|
manifestSkills: manifest.counts.skills,
|
|
55
91
|
backups: {
|
|
56
92
|
exists: existsSync(join(root, '.rsc', 'backups')),
|
|
@@ -285,6 +321,37 @@ export function contextBudget({ target, home = homedir(), cwd = process.cwd() }
|
|
|
285
321
|
+ 'root, or update both to a version that de-duplicates at runtime.',
|
|
286
322
|
});
|
|
287
323
|
}
|
|
324
|
+
const orphanScripts = missingHookScripts({ target, home, cwd });
|
|
325
|
+
if (orphanScripts.length) {
|
|
326
|
+
// ONE finding, not one per file: a clone is missing all eight at once, and a list of
|
|
327
|
+
// eight paths buries the single thing the reader has to do (principle 5).
|
|
328
|
+
findings.push({
|
|
329
|
+
id: 'hook-scripts-missing',
|
|
330
|
+
severity: 'high',
|
|
331
|
+
summary: `${orphanScripts.length} hook script(s) named by the wiring are not on disk, so those hooks `
|
|
332
|
+
+ 'fail every time they fire. This is what a fresh clone looks like: the settings travelled, the '
|
|
333
|
+
+ 'scripts did not.',
|
|
334
|
+
action: 'Rebuild them with `npx @ericrisco/rsc repair` from this project root.',
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
const drift = divergence({ cwd, target, home });
|
|
338
|
+
if (drift.missing.length || drift.extra.length || drift.ownMissing.length) {
|
|
339
|
+
// The day-two case: a teammate changed the harness and this checkout has not caught
|
|
340
|
+
// up. Reported always, even after someone declines to align — the divergence does not
|
|
341
|
+
// stop being true because they said no.
|
|
342
|
+
const parts = [];
|
|
343
|
+
if (drift.missing.length) parts.push(`missing ${drift.missing.join(', ')}`);
|
|
344
|
+
if (drift.ownMissing.length) parts.push(`${drift.ownMissing.join(', ')} declared by the team but not in this repo`);
|
|
345
|
+
if (drift.extra.length) parts.push(`${drift.extra.join(', ')} installed but no longer declared`);
|
|
346
|
+
findings.push({
|
|
347
|
+
id: 'manifest-divergence',
|
|
348
|
+
severity: 'medium',
|
|
349
|
+
summary: `This checkout does not match what .rsc.json declares: ${parts.join('; ')}.`,
|
|
350
|
+
action: drift.ownMissing.length && !drift.missing.length && !drift.extra.length
|
|
351
|
+
? 'Those come from the repo, not from rsc — pull, or ask whoever wrote them.'
|
|
352
|
+
: 'Align with `npx @ericrisco/rsc sync`. Nothing is written until you run it.',
|
|
353
|
+
});
|
|
354
|
+
}
|
|
288
355
|
findings.push(...duplicateEntryFindings(scopes));
|
|
289
356
|
for (const s of scopes) {
|
|
290
357
|
if (s.hookCountsUnknown) {
|