@ericrisco/rsc 3.1.3 → 3.3.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.
- package/README.md +8 -6
- package/manifest.json +43 -69
- package/package.json +6 -1
- package/scripts/design-upstream.js +92 -0
- package/scripts/doctor.js +0 -24
- package/scripts/lib/default-skill-floor.js +5 -1
- package/scripts/lib/domains.js +2 -2
- package/scripts/lib/recommend.js +1 -3
- package/scripts/lib/retired-skills.js +7 -1
- package/skills/ai-media/SKILL.md +2 -2
- package/skills/design/IMPECCABLE-LICENSE.txt +191 -0
- package/skills/design/SKILL.md +79 -328
- package/skills/design/THIRD_PARTY.md +26 -0
- package/skills/design/engine/LICENSE +21 -0
- package/skills/design/engine/RUN.md +515 -0
- package/skills/design/engine/UPSTREAM.json +4 -0
- package/skills/design/engine/assets/app.css +216 -0
- package/skills/design/engine/assets/base.css +105 -0
- package/skills/design/engine/assets/base.js +37 -0
- package/skills/design/engine/assets/charts.js +617 -0
- package/skills/design/engine/assets/scenes/stage.css +28 -0
- package/skills/design/engine/assets/scenes/stage.js +133 -0
- package/skills/design/engine/library/app.json +1327 -0
- package/skills/design/engine/library/directions.json +1078 -0
- package/skills/design/engine/library/heroes.json +1086 -0
- package/skills/design/engine/library/motions.json +92 -0
- package/skills/design/engine/library/palettes.json +1485 -0
- package/skills/design/engine/library/photos.json +7240 -0
- package/skills/design/engine/library/sections.json +4429 -0
- package/skills/design/engine/library/sites.json +8350 -0
- package/skills/design/engine/library/type.json +2024 -0
- package/skills/design/engine/references/app-screens.md +1199 -0
- package/skills/design/engine/references/colour.md +141 -0
- package/skills/design/engine/references/copy.md +177 -0
- package/skills/design/engine/references/critique.md +182 -0
- package/skills/design/engine/references/imagery.md +791 -0
- package/skills/design/engine/references/layout.md +292 -0
- package/skills/design/engine/references/motion.md +980 -0
- package/skills/design/engine/references/research.md +356 -0
- package/skills/design/engine/references/scenes.md +174 -0
- package/skills/design/engine/references/tells.md +115 -0
- package/skills/design/engine/references/type.md +170 -0
- package/skills/design/engine/scripts/assets.mjs +865 -0
- package/skills/design/engine/scripts/draw.mjs +584 -0
- package/skills/design/engine/scripts/inspect.mjs +303 -0
- package/skills/design/engine/scripts/lib/app-draw.mjs +203 -0
- package/skills/design/engine/scripts/lib/cdp.mjs +248 -0
- package/skills/design/engine/scripts/lib/probe.mjs +909 -0
- package/skills/design/engine/scripts/lib/rules.mjs +243 -0
- package/skills/design/engine/scripts/lint.mjs +119 -0
- package/skills/design/engine/scripts/scenes.mjs +124 -0
- package/skills/design/evals/cases.yaml +35 -46
- package/skills/design/references/design-md.md +49 -0
- package/skills/design/references/finish-review.md +46 -0
- package/skills/design/references/modes.md +51 -0
- package/skills/expo/SKILL.md +3 -4
- package/skills/marketing/references/landing-copy.md +2 -2
- package/skills/react/SKILL.md +2 -2
- package/skills/react-native/SKILL.md +3 -3
- package/skills/scroll-film/SKILL.md +220 -0
- package/skills/scroll-film/assets/page-template.html +128 -0
- package/skills/scroll-film/assets/scrub-engine.js +352 -0
- package/skills/scroll-film/evals/README.md +26 -0
- package/skills/scroll-film/evals/cases.yaml +81 -0
- package/skills/scroll-film/references/chain.md +218 -0
- package/skills/scroll-film/references/engine.md +132 -0
- package/skills/scroll-film/scripts/verify.sh +158 -0
- package/skills/swift-ios/SKILL.md +1 -1
- package/skills/ui-engineering/SKILL.md +3 -4
- package/skills/ui-engineering/evals/cases.yaml +2 -2
- package/skills/variant-explorer/SKILL.md +4 -4
- package/skills/variant-explorer/evals/cases.yaml +1 -1
- package/targets/clone-bootstrap.mjs +1 -1
- package/scripts/lib/design-identity.js +0 -117
- package/scripts/lib/starting-point.js +0 -314
- package/skills/design/evals/README.md +0 -53
- package/skills/design/references/ai-tells.md +0 -75
- package/skills/design/references/brand-grounding.md +0 -197
- package/skills/design/references/copywriting-frameworks.md +0 -138
- package/skills/design/references/design-systems.md +0 -49
- package/skills/design/references/inspiration-sources.md +0 -96
- package/skills/design/references/landing-anatomy-and-cro.md +0 -202
- package/skills/design/references/motion-and-interaction.md +0 -228
- package/skills/design/references/research-method.md +0 -154
- package/skills/design/references/signature-and-craft.md +0 -148
- package/skills/design/references/starting-point.md +0 -75
- package/skills/design/references/trends-2026.md +0 -80
- package/skills/design/references/visual-system.md +0 -237
- package/skills/design/scripts/verify.sh +0 -357
- package/skills/design-dna/PROMPT.md +0 -211
- package/skills/design-dna/SKILL.md +0 -162
- package/skills/design-dna/design-dna.schema.json +0 -230
- package/skills/design-dna/evals/README.md +0 -64
- package/skills/design-dna/evals/cases.yaml +0 -68
- package/skills/design-dna/references/method.md +0 -436
- package/skills/design-dna/scripts/emit.py +0 -164
- package/skills/design-dna/templates/PROMPT.md.tmpl +0 -42
- package/skills/design-dna/templates/SKILL.md.tmpl +0 -42
- package/skills/design-dna/templates/check.py.tmpl +0 -143
- package/skills/design-loop/SKILL.md +0 -160
- package/skills/design-loop/evals/README.md +0 -56
- package/skills/design-loop/evals/cases.yaml +0 -60
- package/skills/motion-craft/SKILL.md +0 -125
- package/skills/motion-craft/evals/cases.yaml +0 -38
- package/skills/motion-craft/scripts/verify.sh +0 -75
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
[](https://www.npmjs.com/package/@ericrisco/rsc)
|
|
10
10
|
[](https://www.npmjs.com/package/@ericrisco/rsc)
|
|
11
|
-
[](#the-catalog)
|
|
12
12
|
[](LICENSE)
|
|
13
13
|
[](https://github.com/ericrisco/rsc-harness/stargazers)
|
|
14
14
|
|
|
@@ -60,7 +60,7 @@ The model is the brain your agent rents, and you already have it. rsc adds the r
|
|
|
60
60
|
| --- | --- | --- |
|
|
61
61
|
| **Memory** | `02-DOCS/` | A wiki the agent reads before it works and keeps up to date while it works. |
|
|
62
62
|
| **Hands** | `01-TOOLS/` | One folder per tool, with a test that proves the connection works. |
|
|
63
|
-
| **Trade** | skills | Only the skills your project needs:
|
|
63
|
+
| **Trade** | skills | Only the skills your project needs: 269 available, a handful installed. |
|
|
64
64
|
| **Reflexes** | hooks | Rules that hold even when the agent forgets them mid-session. |
|
|
65
65
|
|
|
66
66
|
### Why documentation comes first
|
|
@@ -468,7 +468,7 @@ snapshots the project first, so `rsc restore latest` undoes a bad update.
|
|
|
468
468
|
|
|
469
469
|
## The catalog
|
|
470
470
|
|
|
471
|
-
|
|
471
|
+
269 skills, grouped by what you are trying to do. Click any skill to read its `SKILL.md`. It fires on
|
|
472
472
|
its own when a task matches.
|
|
473
473
|
|
|
474
474
|
### 🧭 Core & control plane
|
|
@@ -561,11 +561,11 @@ whether, what and which platform.
|
|
|
561
561
|
|
|
562
562
|
### 🌀 Motion & interface craft
|
|
563
563
|
|
|
564
|
-
[
|
|
564
|
+
[ui-engineering](skills/ui-engineering/) · [variant-explorer](skills/variant-explorer/) · [scroll-film](skills/scroll-film/)
|
|
565
565
|
|
|
566
566
|
### 🎨 Design & content craft
|
|
567
567
|
|
|
568
|
-
[design
|
|
568
|
+
[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/)
|
|
569
569
|
|
|
570
570
|
### 🧠 Knowledge & meta
|
|
571
571
|
|
|
@@ -626,8 +626,10 @@ Most of this catalog is written here. These are not, and they keep their author'
|
|
|
626
626
|
| Skills | Source | License |
|
|
627
627
|
| --- | --- | --- |
|
|
628
628
|
| `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 |
|
|
629
|
-
|
|
|
629
|
+
| the engine of `design` (`skills/design/engine/`: direction draw, browser inspector, study library), shipped unmodified | [Leonxlnx/taste-skill](https://github.com/Leonxlnx/taste-skill) v2.1.4 | MIT |
|
|
630
|
+
| the four modes, the fresh review and the `DESIGN.md` record in `design` (text rewritten) | [pbakaus/impeccable](https://github.com/pbakaus/impeccable) by Paul Bakaus, `skill-v4.7.0` | Apache-2.0 |
|
|
630
631
|
| the answer-first habits in `orient` | [ayghri/i-have-adhd](https://github.com/ayghri/i-have-adhd) | MIT |
|
|
632
|
+
| the scroll-scrubbed camera flight, the frame handoff between clips and the phone fixes behind `scroll-film` (prose and engine rewritten) | [oso95/scroll-world](https://github.com/oso95/scroll-world) | MIT |
|
|
631
633
|
|
|
632
634
|
Adapted, not mirrored: each carries rsc frontmatter, routing evals and hand-offs to its siblings. The
|
|
633
635
|
craft bar in them is the original author's.
|
package/manifest.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "3.
|
|
2
|
+
"version": "3.3.0",
|
|
3
3
|
"counts": {
|
|
4
|
-
"skills":
|
|
4
|
+
"skills": 269,
|
|
5
5
|
"agents": 34,
|
|
6
6
|
"commands": 53,
|
|
7
7
|
"fixedCommands": 20
|
|
@@ -124,7 +124,8 @@
|
|
|
124
124
|
"fal",
|
|
125
125
|
"replicate",
|
|
126
126
|
"remotion-video",
|
|
127
|
-
"video-shorts"
|
|
127
|
+
"video-shorts",
|
|
128
|
+
"scroll-film"
|
|
128
129
|
],
|
|
129
130
|
"profiles": []
|
|
130
131
|
},
|
|
@@ -1310,62 +1311,29 @@
|
|
|
1310
1311
|
},
|
|
1311
1312
|
{
|
|
1312
1313
|
"id": "design",
|
|
1313
|
-
"description": "Use when designing or
|
|
1314
|
+
"description": "Use when designing, redesigning, restyling or reviewing a web page or app screen (landing, product site, portfolio, dashboard, docs) or when a UI looks generic or AI-made. Deals a researched direction, takes the idea from the subject, uses real pictures, proves it in a browser. NOT the words (landing-copy), NOT component state (ui-engineering).",
|
|
1314
1315
|
"tags": [
|
|
1315
1316
|
"design",
|
|
1316
|
-
"ux",
|
|
1317
1317
|
"ui",
|
|
1318
|
+
"ux",
|
|
1318
1319
|
"landing",
|
|
1319
|
-
"
|
|
1320
|
+
"dashboard",
|
|
1321
|
+
"frontend",
|
|
1322
|
+
"taste"
|
|
1320
1323
|
],
|
|
1321
1324
|
"recommends": [
|
|
1322
|
-
"
|
|
1323
|
-
"
|
|
1324
|
-
"
|
|
1325
|
-
"
|
|
1325
|
+
"landing-copy",
|
|
1326
|
+
"ui-engineering",
|
|
1327
|
+
"accessibility",
|
|
1328
|
+
"brand-identity",
|
|
1329
|
+
"nextjs"
|
|
1326
1330
|
],
|
|
1327
1331
|
"profiles": [
|
|
1332
|
+
"minimal",
|
|
1333
|
+
"core",
|
|
1328
1334
|
"full"
|
|
1329
1335
|
]
|
|
1330
1336
|
},
|
|
1331
|
-
{
|
|
1332
|
-
"id": "design-dna",
|
|
1333
|
-
"description": "Use when a design has won and its look must survive: codify it into a permanent style skill with measured ratios, bans and tests that can fail, then build new pieces in that exact look. Fires on 'turn this into a skill', 'keep the same style', 'my output drifted'. NOT finding the winner (that is `design-loop`), NOT the words (that is `marketing`).",
|
|
1334
|
-
"tags": [
|
|
1335
|
-
"design",
|
|
1336
|
-
"style",
|
|
1337
|
-
"dna",
|
|
1338
|
-
"codify",
|
|
1339
|
-
"skill-factory",
|
|
1340
|
-
"consistency"
|
|
1341
|
-
],
|
|
1342
|
-
"recommends": [
|
|
1343
|
-
"design-loop",
|
|
1344
|
-
"design",
|
|
1345
|
-
"nextjs",
|
|
1346
|
-
"marketing"
|
|
1347
|
-
],
|
|
1348
|
-
"profiles": []
|
|
1349
|
-
},
|
|
1350
|
-
{
|
|
1351
|
-
"id": "design-loop",
|
|
1352
|
-
"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`).",
|
|
1353
|
-
"tags": [
|
|
1354
|
-
"design",
|
|
1355
|
-
"critique",
|
|
1356
|
-
"loop",
|
|
1357
|
-
"reference",
|
|
1358
|
-
"quality",
|
|
1359
|
-
"convergence"
|
|
1360
|
-
],
|
|
1361
|
-
"recommends": [
|
|
1362
|
-
"design",
|
|
1363
|
-
"design-dna",
|
|
1364
|
-
"marketing",
|
|
1365
|
-
"nextjs"
|
|
1366
|
-
],
|
|
1367
|
-
"profiles": []
|
|
1368
|
-
},
|
|
1369
1337
|
{
|
|
1370
1338
|
"id": "digitalocean",
|
|
1371
1339
|
"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`).",
|
|
@@ -3130,23 +3098,6 @@
|
|
|
3130
3098
|
],
|
|
3131
3099
|
"profiles": []
|
|
3132
3100
|
},
|
|
3133
|
-
{
|
|
3134
|
-
"id": "motion-craft",
|
|
3135
|
-
"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`).",
|
|
3136
|
-
"tags": [
|
|
3137
|
-
"motion",
|
|
3138
|
-
"animation",
|
|
3139
|
-
"interface",
|
|
3140
|
-
"craft",
|
|
3141
|
-
"frontend"
|
|
3142
|
-
],
|
|
3143
|
-
"recommends": [
|
|
3144
|
-
"design"
|
|
3145
|
-
],
|
|
3146
|
-
"profiles": [
|
|
3147
|
-
"full"
|
|
3148
|
-
]
|
|
3149
|
-
},
|
|
3150
3101
|
{
|
|
3151
3102
|
"id": "mysql",
|
|
3152
3103
|
"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`).",
|
|
@@ -4300,6 +4251,30 @@
|
|
|
4300
4251
|
],
|
|
4301
4252
|
"profiles": []
|
|
4302
4253
|
},
|
|
4254
|
+
{
|
|
4255
|
+
"id": "scroll-film",
|
|
4256
|
+
"description": "Use when a page's hero is a pre-rendered camera flight the visitor scrubs by scrolling, Apple-style: AI clips chained frame to frame so seams never pop, encoded for seeking, mounted with an engine that holds up on phones. NOT scroll reveals or pinning (that is `design`), NOT a finished MP4 (that is `ai-media`).",
|
|
4257
|
+
"tags": [
|
|
4258
|
+
"scroll-scrub",
|
|
4259
|
+
"scroll-video",
|
|
4260
|
+
"scrollytelling",
|
|
4261
|
+
"landing-hero",
|
|
4262
|
+
"image-to-video",
|
|
4263
|
+
"camera-flight",
|
|
4264
|
+
"seamless-video"
|
|
4265
|
+
],
|
|
4266
|
+
"recommends": [
|
|
4267
|
+
"ai-media",
|
|
4268
|
+
"fal",
|
|
4269
|
+
"replicate-images",
|
|
4270
|
+
"landing-copy",
|
|
4271
|
+
"design",
|
|
4272
|
+
"performance"
|
|
4273
|
+
],
|
|
4274
|
+
"profiles": [
|
|
4275
|
+
"full"
|
|
4276
|
+
]
|
|
4277
|
+
},
|
|
4303
4278
|
{
|
|
4304
4279
|
"id": "sdd",
|
|
4305
4280
|
"description": "Use when you want a disciplined, spec-driven path from a feature idea to shipped, verified software — the SDD dispatcher and front door, in any language. States the method, reads the user's register from 02-DOCS, and routes to the right phase: constitution -> specify -> clarify -> plan -> tasks -> analyze -> implement -> verify -> review -> ship, with debug / worktrees / parallel on demand. Use it to start a feature, to govern the whole flow, or when unsure which phase you are in. NOT a single phase itself (it dispatches), NOT the workspace harness (that is `harness`), NOT a stack build skill.",
|
|
@@ -5145,8 +5120,7 @@
|
|
|
5145
5120
|
"craft"
|
|
5146
5121
|
],
|
|
5147
5122
|
"recommends": [
|
|
5148
|
-
"design"
|
|
5149
|
-
"motion-craft"
|
|
5123
|
+
"design"
|
|
5150
5124
|
],
|
|
5151
5125
|
"profiles": [
|
|
5152
5126
|
"core",
|
|
@@ -5270,7 +5244,7 @@
|
|
|
5270
5244
|
},
|
|
5271
5245
|
{
|
|
5272
5246
|
"id": "variant-explorer",
|
|
5273
|
-
"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
|
|
5247
|
+
"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`), NOT the spec (`specify`).",
|
|
5274
5248
|
"tags": [
|
|
5275
5249
|
"prototyping",
|
|
5276
5250
|
"divergence",
|
|
@@ -5279,7 +5253,7 @@
|
|
|
5279
5253
|
"decision"
|
|
5280
5254
|
],
|
|
5281
5255
|
"recommends": [
|
|
5282
|
-
"design
|
|
5256
|
+
"design"
|
|
5283
5257
|
],
|
|
5284
5258
|
"profiles": [
|
|
5285
5259
|
"full"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ericrisco/rsc",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.3.0",
|
|
4
4
|
"description": "A guided harness builder that turns your goal into a minimal, verified AI-agent setup using strict best practices.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"knowledge:doctor": "node scripts/knowledge-doctor.js",
|
|
20
20
|
"spec:gate": "node scripts/spec-gate.js",
|
|
21
21
|
"routing:audit": "node scripts/routing-audit.js",
|
|
22
|
+
"design:upstream": "node scripts/design-upstream.js",
|
|
22
23
|
"originality:check": "node scripts/originality-check.js",
|
|
23
24
|
"test": "node --test",
|
|
24
25
|
"coverage": "c8 --reporter=text node --test",
|
|
@@ -115,6 +116,10 @@
|
|
|
115
116
|
{
|
|
116
117
|
"fixedIn": "2.1.0",
|
|
117
118
|
"symptom": "Answers were long and leaned on hidden reasoning, and onboarding asked an accompaniment level few could answer; now: short stand-alone sentences, one question"
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
"fixedIn": "3.3.0",
|
|
122
|
+
"symptom": "Pages and screens designed with rsc came out generic and AI-looking, and most projects had no design skill installed at all (found by Carlos del Corral)"
|
|
118
123
|
}
|
|
119
124
|
]
|
|
120
125
|
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// design-upstream.js — is the `design` engine behind the projects it comes from?
|
|
3
|
+
//
|
|
4
|
+
// `skills/design/engine/` is taste-skill shipped unmodified, and three of its references adapt
|
|
5
|
+
// impeccable's text. Both upstreams ship weekly. Nothing reminded anyone, so the previous design
|
|
6
|
+
// skill drifted into the state that got it rebuilt (spec design-from-scratch). This is the reminder.
|
|
7
|
+
//
|
|
8
|
+
// node scripts/design-upstream.js report: silent and exit 0 when current,
|
|
9
|
+
// one line per upstream that moved and exit 1
|
|
10
|
+
// node scripts/design-upstream.js --sync DIR copy a REVIEWED taste-skill checkout over engine/
|
|
11
|
+
//
|
|
12
|
+
// It never downloads code to apply it. Bringing a new version in is a person reading the diff and
|
|
13
|
+
// running --sync on a checkout they cloned themselves (a public skill is untrusted input).
|
|
14
|
+
import { readFileSync, writeFileSync, rmSync, cpSync, existsSync } from 'node:fs';
|
|
15
|
+
import { join, dirname } from 'node:path';
|
|
16
|
+
import { fileURLToPath } from 'node:url';
|
|
17
|
+
import { execFileSync } from 'node:child_process';
|
|
18
|
+
|
|
19
|
+
const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..');
|
|
20
|
+
export const ENGINE = join(ROOT, 'skills', 'design', 'engine');
|
|
21
|
+
const RUNTIME = ['scripts', 'library', 'assets', 'references'];
|
|
22
|
+
|
|
23
|
+
export function readUpstream(engine = ENGINE) {
|
|
24
|
+
return JSON.parse(readFileSync(join(engine, 'UPSTREAM.json'), 'utf8'));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async function getJson(fetchImpl, url) {
|
|
28
|
+
const res = await fetchImpl(url, { headers: { accept: 'application/vnd.github+json', 'user-agent': 'rsc-design-upstream' } });
|
|
29
|
+
if (!res.ok) throw new Error(`${url} → HTTP ${res.status}`);
|
|
30
|
+
return res.json();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** One entry per upstream that moved; an empty list means the engine is current. */
|
|
34
|
+
export async function checkUpstream({ upstream = readUpstream(), fetchImpl = fetch } = {}) {
|
|
35
|
+
const moved = [];
|
|
36
|
+
const t = upstream['taste-skill'];
|
|
37
|
+
const commits = await getJson(fetchImpl, `https://api.github.com/repos/${t.repo}/commits?path=${t.path}&per_page=1`);
|
|
38
|
+
const latest = commits[0]?.sha;
|
|
39
|
+
// Different ids do not mean newer: the shipped commit is often a merge that already contains the
|
|
40
|
+
// latest commit on the path. Only a latest commit AHEAD of what shipped is news.
|
|
41
|
+
const ahead = latest && latest !== t.commit
|
|
42
|
+
&& ['ahead', 'diverged'].includes((await getJson(fetchImpl, `https://api.github.com/repos/${t.repo}/compare/${t.commit}...${latest}`)).status);
|
|
43
|
+
if (ahead) {
|
|
44
|
+
moved.push({ id: 'taste-skill', shipped: t.commit.slice(0, 7), latest: latest.slice(0, 7), url: `https://github.com/${t.repo}/compare/${t.commit}...${latest}` });
|
|
45
|
+
}
|
|
46
|
+
const i = upstream.impeccable;
|
|
47
|
+
const releases = await getJson(fetchImpl, `https://api.github.com/repos/${i.repo}/releases?per_page=30`);
|
|
48
|
+
const skill = releases.find((r) => typeof r.tag_name === 'string' && r.tag_name.startsWith('skill-v'));
|
|
49
|
+
if (skill && skill.tag_name !== i.version) {
|
|
50
|
+
moved.push({ id: 'impeccable', shipped: i.version, latest: skill.tag_name, url: `https://github.com/${i.repo}/releases/tag/${skill.tag_name}` });
|
|
51
|
+
}
|
|
52
|
+
return moved;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Copy a reviewed taste-skill checkout over engine/, and record which commit it was. */
|
|
56
|
+
export function syncTaste(checkout, engine = ENGINE) {
|
|
57
|
+
const src = join(checkout, 'skills', 'taste-skill');
|
|
58
|
+
if (!existsSync(join(src, 'SKILL.md'))) throw new Error(`${checkout} is not a taste-skill checkout (no skills/taste-skill/SKILL.md)`);
|
|
59
|
+
for (const dir of RUNTIME) {
|
|
60
|
+
rmSync(join(engine, dir), { recursive: true, force: true });
|
|
61
|
+
if (existsSync(join(src, dir))) cpSync(join(src, dir), join(engine, dir), { recursive: true });
|
|
62
|
+
}
|
|
63
|
+
cpSync(join(checkout, 'LICENSE'), join(engine, 'LICENSE'));
|
|
64
|
+
// RUN.md is the upstream SKILL.md without its front matter, so it is never discovered as a skill.
|
|
65
|
+
writeFileSync(join(engine, 'RUN.md'), readFileSync(join(src, 'SKILL.md'), 'utf8').replace(/^---\n[\s\S]*?\n---\n/, ''));
|
|
66
|
+
const upstream = readUpstream(engine);
|
|
67
|
+
// The last commit that touched the skill folder; checkUpstream asks GitHub whether anything newer
|
|
68
|
+
// on that path is ahead of it.
|
|
69
|
+
upstream['taste-skill'].commit = execFileSync('git', ['-C', checkout, 'log', '-1', '--format=%H', '--', 'skills/taste-skill'], { encoding: 'utf8' }).trim();
|
|
70
|
+
const changelog = join(checkout, 'CHANGELOG.md');
|
|
71
|
+
const version = existsSync(changelog) && /^## (\d+\.\d+\.\d+)/m.exec(readFileSync(changelog, 'utf8'));
|
|
72
|
+
if (version) upstream['taste-skill'].version = version[1];
|
|
73
|
+
writeFileSync(join(engine, 'UPSTREAM.json'), `${JSON.stringify(upstream, null, 2)}\n`);
|
|
74
|
+
return upstream['taste-skill'];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async function main() {
|
|
78
|
+
const at = process.argv.indexOf('--sync');
|
|
79
|
+
if (at !== -1) {
|
|
80
|
+
const synced = syncTaste(process.argv[at + 1]);
|
|
81
|
+
console.log(`engine synced to taste-skill ${synced.version} (${synced.commit.slice(0, 7)}). Run the tests and read the diff before committing.`);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
const moved = await checkUpstream();
|
|
85
|
+
for (const m of moved) console.log(`${m.id}: shipped ${m.shipped}, upstream ${m.latest} → ${m.url}`);
|
|
86
|
+
if (moved.length) {
|
|
87
|
+
console.log('Review the change, clone it yourself, then: node scripts/design-upstream.js --sync <taste-skill checkout>');
|
|
88
|
+
process.exitCode = 1;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (import.meta.url === `file://${process.argv[1]}`) main().catch((e) => { console.error(e.message); process.exitCode = 2; });
|
package/scripts/doctor.js
CHANGED
|
@@ -11,8 +11,6 @@ import { readManifest as readProjectManifest } from './lib/manifest-file.js';
|
|
|
11
11
|
import { listBackups } from './lib/backups.js';
|
|
12
12
|
import { SDD_GATE_TEXT } from '../targets/hook-once.mjs';
|
|
13
13
|
import { isEnabled, checkSello, readSello, countFindings, readEffectiveConfig, validateRiskConfig } from '../targets/sello.mjs';
|
|
14
|
-
import { designIdentity } from './lib/design-identity.js';
|
|
15
|
-
import { startingPointSummary } from './lib/starting-point.js';
|
|
16
14
|
import { countGaps, listSkills, listAgents } from './lib/capabilities.js';
|
|
17
15
|
import { resolveCommands, commandPath, targetHasCommands } from '../targets/commands.js';
|
|
18
16
|
import { inspectMemoryWiring } from '../targets/memory.js';
|
|
@@ -104,17 +102,6 @@ export function missingHookScripts({ target, home = homedir(), cwd = process.cwd
|
|
|
104
102
|
// Is the post-merge trigger actually armed in this clone? Three states, because they need three
|
|
105
103
|
// different answers: armed, absent (repair it), or someone else's (leave it — chaining is our job
|
|
106
104
|
// at install time, and overwriting a husky hook to fix a convenience would be indefensible).
|
|
107
|
-
// The skills that read or write a design identity (02-DOCS/wiki/brand/) or a starting point. The
|
|
108
|
-
// state is always reported; the FIX — "run design-loop, then design-dna" — is advice, and advice needs
|
|
109
|
-
// evidence. A todo web app with none of these installed was told to run two skills it does not have
|
|
110
|
-
// and never asked for (E2E 2026-10-07).
|
|
111
|
-
const DESIGN_SKILLS = new Set(['design', 'design-loop', 'design-dna', 'brand-voice', 'content-engine', 'marketing', 'presentations', 'make']);
|
|
112
|
-
function withoutUnfoundedFix(summary, inPlay) {
|
|
113
|
-
if (inPlay || !summary || !summary.fix) return summary;
|
|
114
|
-
const { fix, ...rest } = summary;
|
|
115
|
-
return { ...rest, note: 'no design skill is installed here, so nothing is recommended' };
|
|
116
|
-
}
|
|
117
|
-
|
|
118
105
|
function worktreeCleanupStatus(root, policy) {
|
|
119
106
|
if (!existsSync(join(root, '.git'))) return { state: 'not-a-repo' };
|
|
120
107
|
if (existsSync(join(root, '.rsc', '.no-worktree-cleanup'))) return { state: 'off-by-choice' };
|
|
@@ -250,9 +237,6 @@ export function doctor({ target, home, cwd }) {
|
|
|
250
237
|
const path = agentPath(target, root, id);
|
|
251
238
|
return path && !existsSync(path);
|
|
252
239
|
}).map((id) => ({ id, path: agentPath(target, root, id), action: 'Run `npx @ericrisco/rsc sync` to restore this managed agent.' }));
|
|
253
|
-
// What THIS harness installed, not every skill visible from here: a design skill in the user's
|
|
254
|
-
// global scope is how a todo app's doctor came to recommend design-dna (E2E 2026-10-07).
|
|
255
|
-
const designInPlay = Object.keys(state.skills || {}).some((id) => DESIGN_SKILLS.has(id));
|
|
256
240
|
const report = {
|
|
257
241
|
target,
|
|
258
242
|
installed: Object.keys(state.skills),
|
|
@@ -273,14 +257,6 @@ export function doctor({ target, home, cwd }) {
|
|
|
273
257
|
worktreeHygiene: worktreeHygiene(root),
|
|
274
258
|
ownSkills: ownSkillsIn(paths, readProjectManifest(root)?.ownSkills || []),
|
|
275
259
|
sello: selloStatus(root),
|
|
276
|
-
// Whether this harness has a design identity at all. `design` has always DECLARED that it
|
|
277
|
-
// stops without one; until lib/design-identity.js nothing checked it (P2). Reported here,
|
|
278
|
-
// never nagged about and never blocking: a missing identity is low risk (P7).
|
|
279
|
-
designIdentity: withoutUnfoundedFix(designIdentity(root), designInPlay),
|
|
280
|
-
// The other half of the same question: an identity is what this project settled on, a starting
|
|
281
|
-
// point is what it has to settle FROM. Three skills promise to propose one and none could look;
|
|
282
|
-
// this is the look. One field, not a section — a report grows for every user who runs it (P5).
|
|
283
|
-
designStartingPoint: withoutUnfoundedFix(startingPointSummary(root), designInPlay),
|
|
284
260
|
// An inert gate must never read as an armed one (the same rule the sello follows):
|
|
285
261
|
// the gitmoji guard has a per-project kill switch, so say which state it is in.
|
|
286
262
|
gitmojiGuard: state.policy?.gitmojiGuard === false
|
|
@@ -14,7 +14,11 @@
|
|
|
14
14
|
// `connect-tool` joined in 3.0.13 (issue #303): rsc ships no ready-made connections, so "connect my
|
|
15
15
|
// Holded" is answered by a method, not a list, and that method has to be there the first time the
|
|
16
16
|
// user asks, in any kind of project. Like `unslop`, only its description is paid for on other turns.
|
|
17
|
-
|
|
17
|
+
//
|
|
18
|
+
// `design` joined in 3.3.0 (spec design-from-scratch): it was `full`-only, so most projects designed
|
|
19
|
+
// with no design skill at all. Only its description is paid for on other turns; the engine it ships
|
|
20
|
+
// (scripts and data) is never loaded into context.
|
|
21
|
+
export const DEFAULT_SKILL_FLOOR = Object.freeze(['orient', 'suggest', 'unslop', 'ftd', 'connect-tool', 'design']);
|
|
18
22
|
|
|
19
23
|
export function withDefaultSkillFloor(skillIds = []) {
|
|
20
24
|
return [...new Set([...DEFAULT_SKILL_FLOOR, ...skillIds])];
|
package/scripts/lib/domains.js
CHANGED
|
@@ -24,8 +24,8 @@ export const DOMAINS = [
|
|
|
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: ['
|
|
28
|
-
{ title: 'Design & content craft', ids: ['design
|
|
27
|
+
{ title: 'Motion & interface craft', ids: ['ui-engineering', 'variant-explorer', 'scroll-film'] },
|
|
28
|
+
{ title: 'Design & content craft', ids: ['design', 'presentations', 'course-storytelling', 'course-builder', 'technical-writing', 'translation-l10n'] },
|
|
29
29
|
{ title: 'Knowledge & meta', ids: ['knowledge-ops', 'codebase-onboarding', 'research-ops', 'decision-records', 'continuous-learning', 'skill-scout', 'context-budget', 'roast-me', 'fable-operator'] },
|
|
30
30
|
];
|
|
31
31
|
|
package/scripts/lib/recommend.js
CHANGED
|
@@ -10,9 +10,7 @@ const OUTCOMES = {
|
|
|
10
10
|
fastapi: 'Your API / Python backend',
|
|
11
11
|
go: 'Your Go backend service',
|
|
12
12
|
postgresdb: 'Store your data reliably',
|
|
13
|
-
design: '
|
|
14
|
-
'design-loop': 'Make it as good as the site you admire',
|
|
15
|
-
'design-dna': 'Keep every page looking like yours',
|
|
13
|
+
design: 'Pages and screens that look designed, not generated',
|
|
16
14
|
marketing: 'Copy that sells',
|
|
17
15
|
presentations: 'On-brand presentations',
|
|
18
16
|
'course-storytelling': 'Teach so it actually lands',
|
|
@@ -8,7 +8,13 @@
|
|
|
8
8
|
//
|
|
9
9
|
// `targets/clone-bootstrap.mjs` is committed into user repos and cannot import this file; it carries
|
|
10
10
|
// an inline copy, and tests/retired-skills.test.js holds the two equal in behaviour.
|
|
11
|
-
|
|
11
|
+
//
|
|
12
|
+
// `design-loop`, `design-dna` and `motion-craft` folded into the rebuilt `design` in 3.3.0 (spec
|
|
13
|
+
// design-from-scratch): its engine deals the direction, measures the render and owns the motion layer.
|
|
14
|
+
export const RETIRED_SKILLS = Object.freeze({
|
|
15
|
+
eli5: 'orient', 'show-me': 'orient', bro: 'unslop',
|
|
16
|
+
'design-loop': 'design', 'design-dna': 'design', 'motion-craft': 'design',
|
|
17
|
+
});
|
|
12
18
|
|
|
13
19
|
const retiredTo = (id) => (Object.hasOwn(RETIRED_SKILLS, id) ? RETIRED_SKILLS[id] : id);
|
|
14
20
|
|
package/skills/ai-media/SKILL.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: ai-media
|
|
3
3
|
description: "Use when a creative goal must become a finished media file: pick and order generative-media models per modality — AI voiceover, image-to-video clips, score — then glue them with ffmpeg (mux, duck, loudnorm, concat). NOT still-image generation/editing (that is `replicate-images`); NOT code-rendered React compositing (that is `remotion-video`)."
|
|
4
4
|
tags: [ai-media, text-to-speech, image-to-video, voiceover, music-generation, ffmpeg, media-pipeline, elevenlabs]
|
|
5
|
-
recommends: [replicate-images, fal, replicate, remotion-video, video-shorts]
|
|
5
|
+
recommends: [replicate-images, fal, replicate, remotion-video, video-shorts, scroll-film]
|
|
6
6
|
origin: risco
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -23,7 +23,7 @@ Map the goal to modalities and an ordered step list, and **lock that plan before
|
|
|
23
23
|
| Just a clip from a still | img→video only | still (input) → clip | `fal`/`replicate` |
|
|
24
24
|
| Code-rendered explainer | none of the above | render from React/TS | **stop — route to `remotion-video`** |
|
|
25
25
|
|
|
26
|
-
If the video is *rendered from data/code* (charts, timelines, JSON-driven scenes), this is not your job → `../remotion-video/SKILL.md`. You handle *model-generated + ffmpeg-glued*.
|
|
26
|
+
If the video is *rendered from data/code* (charts, timelines, JSON-driven scenes), this is not your job → `../remotion-video/SKILL.md`. You handle *model-generated + ffmpeg-glued*. If the clips will be scrubbed by scroll on a page instead of played as a file, the chain, its seams and the page are `../scroll-film/SKILL.md`.
|
|
27
27
|
|
|
28
28
|
## Modality 1 — Voice (TTS)
|
|
29
29
|
|