@radicool/throughline 0.14.0 → 0.16.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 +2 -1
- package/adapters/codex/AGENTS.md +10 -10
- package/adapters/codex/prompts/component-builder.md +59 -15
- package/adapters/codex/prompts/document-component.md +42 -10
- package/adapters/codex/prompts/storybook-chromatic-builder.md +52 -9
- package/adapters/codex/prompts/token-crosswalk-builder.md +2 -0
- package/adapters/codex/prompts/token-sync-layer.md +64 -4
- package/adapters/cursor/.cursor/commands/document-component.md +42 -10
- package/adapters/cursor/.cursor/rules/component-builder.mdc +60 -16
- package/adapters/cursor/.cursor/rules/component-pipeline.mdc +1 -1
- package/adapters/cursor/.cursor/rules/design-system-audit.mdc +1 -1
- package/adapters/cursor/.cursor/rules/figma-environment-setup.mdc +1 -1
- package/adapters/cursor/.cursor/rules/icon-system-builder.mdc +1 -1
- package/adapters/cursor/.cursor/rules/repository-builder.mdc +1 -1
- package/adapters/cursor/.cursor/rules/retrofit-planner.mdc +1 -1
- package/adapters/cursor/.cursor/rules/storybook-chromatic-builder.mdc +53 -10
- package/adapters/cursor/.cursor/rules/token-builder.mdc +1 -1
- package/adapters/cursor/.cursor/rules/token-crosswalk-builder.mdc +3 -1
- package/adapters/cursor/.cursor/rules/token-sheet-builder.mdc +1 -1
- package/adapters/cursor/.cursor/rules/token-sync-layer.mdc +65 -5
- package/adapters/generic/AGENTS.md +10 -10
- package/adapters/generic/commands/document-component.md +42 -10
- package/adapters/generic/skills/component-builder/SKILL.md +59 -15
- package/adapters/generic/skills/storybook-chromatic-builder/SKILL.md +52 -9
- package/adapters/generic/skills/token-crosswalk-builder/SKILL.md +2 -0
- package/adapters/generic/skills/token-sync-layer/SKILL.md +64 -4
- package/package.json +1 -1
- package/references/component-doc-archetypes.md +15 -11
- package/references/component-doc-schema.md +23 -5
- package/references/doc-card-builder.md +565 -0
- package/references/doc-writing-standard.md +144 -0
- package/references/figma-component-standards.md +63 -16
- package/references/guide-voice.md +96 -0
- package/references/manifest-schema.md +24 -6
- package/references/native-adapter-config.md +930 -0
- package/references/sync-adapters.md +94 -12
- package/scripts/README.md +37 -3
- package/scripts/build-doc-card-builder.mjs +143 -0
- package/scripts/build-native-adapter-config.mjs +280 -0
- package/scripts/docs-check.mjs +18 -4
- package/scripts/docs-lint.mjs +163 -0
- package/scripts/install.mjs +14 -1
- package/scripts/lib/doc-card-plan.mjs +101 -0
- package/scripts/lib/doc-card-render.figma.js +371 -0
- package/scripts/lib/dtcg.mjs +87 -0
- package/scripts/lib/native-literal.mjs +205 -0
- package/scripts/lib/sd-native.mjs +770 -0
- package/scripts/validate-crosswalk.mjs +3 -29
- package/scripts/validate-token-output.mjs +338 -0
|
@@ -44,8 +44,8 @@ Ask which platform(s) the user is building for. Read
|
|
|
44
44
|
- **Curated (Tier 1):** `shadcn`, `tailwind`, `mui`, `vanilla-css`, `ios-swift`.
|
|
45
45
|
Vetted presets — high confidence.
|
|
46
46
|
- **Generated (Tier 2):** any other framework (Ant Design, Chakra, HeroUI,
|
|
47
|
-
Android/Kotlin, Flutter, etc.). The skill generates an adapter and
|
|
48
|
-
against a real component before trusting it.
|
|
47
|
+
Android/Kotlin, Flutter, etc.). The skill generates an adapter and
|
|
48
|
+
verifies it against a real component before trusting it.
|
|
49
49
|
|
|
50
50
|
**Always tell the user which tier they're on.** If they name a curated one, say
|
|
51
51
|
it'll be solid. If they name anything else, be honest: "That's not one I have a
|
|
@@ -139,11 +139,53 @@ register the platform, transform group, format, and `outputReferences`
|
|
|
139
139
|
flattens). Web adapters emit `:root`/`.dark` (or `[data-theme]`); the shadcn
|
|
140
140
|
adapter also emits a Tailwind preset.
|
|
141
141
|
|
|
142
|
+
**Native targets import the shipped configuration; they do not transcribe it.**
|
|
143
|
+
Copy `.throughline/scripts/lib/sd-native.mjs` into
|
|
144
|
+
`packages/tokens/scripts/lib/` (see Step 4) and call it. The stock `ios-swift`
|
|
145
|
+
and `compose` transform groups emit every `px`-authored dimension at ×16 its
|
|
146
|
+
value — valid, compiling, silently wrong — and mishandle `color-mix()` and
|
|
147
|
+
dual-node DTCG the same way. Never build a native platform from a stock
|
|
148
|
+
`transformGroup`.
|
|
149
|
+
|
|
150
|
+
```js
|
|
151
|
+
import StyleDictionary from 'style-dictionary';
|
|
152
|
+
import { registerNativeTransforms, nativePlatform, nativeSources }
|
|
153
|
+
from './scripts/lib/sd-native.mjs';
|
|
154
|
+
|
|
155
|
+
registerNativeTransforms(StyleDictionary);
|
|
156
|
+
|
|
157
|
+
for (const mode of MODES) { // e.g. ['light', 'dark']
|
|
158
|
+
const sd = new StyleDictionary({
|
|
159
|
+
source: nativeSources(sourcesFor(mode)), // guards against a mode collapse
|
|
160
|
+
preprocessors: ['dtcg/resolve-dual-node'],
|
|
161
|
+
platforms: {
|
|
162
|
+
ios: nativePlatform({ platform: 'ios-swift', buildPath: `ios/${mode}/` }),
|
|
163
|
+
// android also requires packageName:
|
|
164
|
+
// android: nativePlatform({ platform: 'android-kotlin',
|
|
165
|
+
// buildPath: `android/${mode}/`, packageName: 'com.example.tokens' }),
|
|
166
|
+
},
|
|
167
|
+
});
|
|
168
|
+
await sd.buildAllPlatforms();
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
**One build per mode combination, and never a glob.** Style Dictionary dedupes
|
|
173
|
+
by dot-path, so a single build over the whole token directory collapses light
|
|
174
|
+
and dark into whichever file sorted last, silently dropping a mode. Passing each
|
|
175
|
+
mode's sources through `nativeSources` turns that into a thrown error naming the
|
|
176
|
+
colliding paths. The `dtcg/resolve-dual-node` preprocessor throws too, on its
|
|
177
|
+
own collision: a dual node's hoisted child renamed to a camel-joined name that
|
|
178
|
+
an existing sibling or an earlier hoist in the same pass already has. Then run
|
|
179
|
+
`tokens:validate-output` against each generated file with that same source
|
|
180
|
+
list. See `.throughline/references/native-adapter-config.md`.
|
|
181
|
+
|
|
142
182
|
**Execution model — subagent dispatch with model routing.** Generating each
|
|
143
183
|
platform's output is independent and verifiable. If your host supports subagent
|
|
144
184
|
dispatch, dispatch **one `code-executor` per adapter** — each produces its
|
|
145
|
-
platform's files and verifies them (the config builds, the expected
|
|
146
|
-
appear, references resolve for
|
|
185
|
+
platform's files and verifies them (for web: the config builds, the expected
|
|
186
|
+
files appear, references resolve; for native: `tokens:validate-output` passes —
|
|
187
|
+
"the config builds" is not verification, it is the condition under which all
|
|
188
|
+
four known native failure modes ship silently) — then a **`reviewer`**
|
|
147
189
|
to check each before combining. Choose each subagent's model from its role tier
|
|
148
190
|
per `.throughline/references/agent-routing.md` (`code-executor` → fast,
|
|
149
191
|
`reviewer` → balanced), and only dispatch once each adapter's spec is complete
|
|
@@ -159,6 +201,24 @@ as **build artifacts** — regenerated every sync, never hand-edited. Wire
|
|
|
159
201
|
`packages/tokens/package.json` to export them so the UI package, Storybook, and
|
|
160
202
|
any future app consume them.
|
|
161
203
|
|
|
204
|
+
**Install the native token toolkit — all four files, as a set.** Copy
|
|
205
|
+
`.throughline/scripts/validate-token-output.mjs` into
|
|
206
|
+
`packages/tokens/scripts/`, and
|
|
207
|
+
`.throughline/scripts/lib/dtcg.mjs`,
|
|
208
|
+
`.throughline/scripts/lib/native-literal.mjs`, and
|
|
209
|
+
`.throughline/scripts/lib/sd-native.mjs` into
|
|
210
|
+
`packages/tokens/scripts/lib/`. `sd-native.mjs` and the validator both import
|
|
211
|
+
`dtcg.mjs` and `native-literal.mjs`, so copying any of them without the others
|
|
212
|
+
breaks at import. Then register the gate so it stays live on every future sync:
|
|
213
|
+
|
|
214
|
+
```json
|
|
215
|
+
"tokens:validate-output": "node scripts/validate-token-output.mjs --min-match 1"
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
Invoke it once per native output file, passing the same `--source` list that
|
|
219
|
+
file's build used. `--min-match 1` is what makes it a gate: the flag defaults to
|
|
220
|
+
`0.5`, so without it a 60% match rate exits `0`.
|
|
221
|
+
|
|
162
222
|
## Step 4.5 — Icon code sync (install check + custom SVGR)
|
|
163
223
|
|
|
164
224
|
Icons reach code differently from tokens, so handle them here if the system has
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@radicool/throughline",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"description": "Build a complete design system end to end — author in Figma, sync tokens to code, generate Storybook. Usable from Claude Code, Cursor, Codex, or any AGENTS.md agent.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -12,14 +12,16 @@ These are **seeds, not gospel** — the user's approval and the actual built
|
|
|
12
12
|
component override them. Sources: W3C ARIA Authoring Practices Guide (roles +
|
|
13
13
|
keyboard), Material 3, Shopify Polaris (content/usage), IBM Carbon (usage).
|
|
14
14
|
|
|
15
|
+
Seeds are clause-style shorthand; the authoring pipeline expands them into full sentences per references/doc-writing-standard.md before they enter a record.
|
|
16
|
+
|
|
15
17
|
## Button
|
|
16
18
|
|
|
17
19
|
- **whenToUse:** trigger an action or event (submit, confirm, open a dialog).
|
|
18
|
-
- **whenNotToUse:** navigation between pages/URLs
|
|
20
|
+
- **whenNotToUse:** navigation between pages/URLs (use a Link).
|
|
19
21
|
- **dos:** lead the label with a verb; keep one primary (highest-emphasis) button
|
|
20
22
|
per view; keep labels short (≤ ~3 words).
|
|
21
|
-
- **donts:** don't use a button for navigation; don't stack multiple
|
|
22
|
-
buttons; don't disable without telling the user why.
|
|
23
|
+
- **donts:** don't use a button for navigation (use a Link); don't stack multiple
|
|
24
|
+
primary buttons (keep one per view); don't disable without telling the user why.
|
|
23
25
|
- **accessibility (w3c-apg):** role `button`; Enter and Space activate; an
|
|
24
26
|
icon-only button needs an `aria-label`; disabled buttons are not focusable.
|
|
25
27
|
|
|
@@ -30,8 +32,8 @@ keyboard), Material 3, Shopify Polaris (content/usage), IBM Carbon (usage).
|
|
|
30
32
|
text (use Textarea).
|
|
31
33
|
- **dos:** always pair with a visible label; show format hints as helper text;
|
|
32
34
|
reserve space for error text to avoid layout shift.
|
|
33
|
-
- **donts:** don't use placeholder text as the only label
|
|
34
|
-
keystroke before first blur.
|
|
35
|
+
- **donts:** don't use placeholder text as the only label (pair with a visible
|
|
36
|
+
label); don't validate on every keystroke before first blur.
|
|
35
37
|
- **accessibility (w3c-apg):** every input has a programmatically associated
|
|
36
38
|
`<label>`; error state sets `aria-invalid` and links the message via
|
|
37
39
|
`aria-describedby`.
|
|
@@ -42,8 +44,8 @@ keyboard), Material 3, Shopify Polaris (content/usage), IBM Carbon (usage).
|
|
|
42
44
|
- **whenNotToUse:** a single either/or action that takes effect immediately with no
|
|
43
45
|
save (prefer a toggle) vs. a form choice (prefer radio/checkbox).
|
|
44
46
|
- **dos:** label the control, not just the group; make the label clickable.
|
|
45
|
-
- **donts:** don't use a radio group for multi-select; don't use
|
|
46
|
-
|
|
47
|
+
- **donts:** don't use a radio group for multi-select (use checkboxes); don't use
|
|
48
|
+
a toggle for choices needing a separate Save (use radio/checkbox).
|
|
47
49
|
- **accessibility (w3c-apg):** roles `checkbox` / `radio` / `switch`; Space
|
|
48
50
|
toggles; radio groups navigate with arrow keys; state exposed via
|
|
49
51
|
`aria-checked`.
|
|
@@ -51,7 +53,8 @@ keyboard), Material 3, Shopify Polaris (content/usage), IBM Carbon (usage).
|
|
|
51
53
|
## Card
|
|
52
54
|
|
|
53
55
|
- **whenToUse:** group related content and actions about a single subject.
|
|
54
|
-
- **whenNotToUse:** primary page layout scaffolding
|
|
56
|
+
- **whenNotToUse:** primary page layout scaffolding (use a layout/grid component); a
|
|
57
|
+
bare list of text (use a List).
|
|
55
58
|
- **dos:** make the primary action obvious; keep one main call-to-action per card.
|
|
56
59
|
- **donts:** don't nest cards more than one level; don't make the whole card AND an
|
|
57
60
|
inner button separately clickable in conflicting ways.
|
|
@@ -71,10 +74,11 @@ keyboard), Material 3, Shopify Polaris (content/usage), IBM Carbon (usage).
|
|
|
71
74
|
## Badge / chip / tag
|
|
72
75
|
|
|
73
76
|
- **whenToUse:** short status, count, or category label (badge); a removable/
|
|
74
|
-
selectable
|
|
77
|
+
selectable item (chip).
|
|
75
78
|
- **whenNotToUse:** interactive primary actions (use a Button).
|
|
76
|
-
- **dos:** keep text to a word or two;
|
|
77
|
-
|
|
79
|
+
- **dos:** keep text to a word or two; match badge color to its semantic meaning
|
|
80
|
+
(success, warning, error).
|
|
81
|
+
- **donts:** don't rely on color alone to convey status (include text or an icon).
|
|
78
82
|
- **accessibility:** a removable chip's remove control needs an accessible name
|
|
79
83
|
(e.g. "Remove <label>"); status conveyed with text, not color only (WCAG 1.4.1).
|
|
80
84
|
|
|
@@ -58,9 +58,17 @@ deterministically. JSON is equally machine-legible for AI consumers.
|
|
|
58
58
|
- **Lifecycle:** `status` (`draft`|`beta`|`stable`|`deprecated`), `updatedAt` (ISO date).
|
|
59
59
|
- **`provenance`** — per-block author source, one of `imported`, `ai-inferred`,
|
|
60
60
|
`best-practice`, `w3c-apg`, `framework`, `user`, or a `+`-joined combination
|
|
61
|
-
(e.g. `best-practice+user`). Regeneration re-infers
|
|
62
|
-
|
|
63
|
-
`imported`.
|
|
61
|
+
(e.g. `best-practice+user`). Regeneration **re-infers** a block whose
|
|
62
|
+
provenance includes `ai-inferred`, `framework`, `best-practice`, or `w3c-apg`,
|
|
63
|
+
and **never overwrites** one whose provenance includes `user` or `imported`.
|
|
64
|
+
Every value is assigned to exactly one of those two tiers: generated content is
|
|
65
|
+
re-inferred, human input (`user`) and pre-existing external content
|
|
66
|
+
(`imported`) are protected. Protection takes precedence: a combination that
|
|
67
|
+
contains both — `best-practice+user`, say — is protected. A block is
|
|
68
|
+
re-inferred only when it carries no `user` or `imported` marker at all. A
|
|
69
|
+
protected block may still be rewritten when the user approves the rewrite at
|
|
70
|
+
the record-approval gate; the result is stamped `imported+user`, which is
|
|
71
|
+
protected from then on and never re-proposed.
|
|
64
72
|
|
|
65
73
|
Deferred to a later version (do not emit in v1): `anatomy`, `content` (writing
|
|
66
74
|
guidelines), `examples`.
|
|
@@ -84,7 +92,7 @@ Figma-connected skill computing the identical hash over the description content.
|
|
|
84
92
|
|---|---|---|---|---|
|
|
85
93
|
| summary, description | ✔ | ✔ | ✔ | ✔ |
|
|
86
94
|
| whenToUse / whenNotToUse | ✔ | ✔ | ✔ | ✔ |
|
|
87
|
-
| variants, states (meanings) |
|
|
95
|
+
| variants, states (meanings) | — | ✔ legend | ✔ argTypes | ✔ |
|
|
88
96
|
| dos / donts | ✔ | ✔ | ✔ | ✔ |
|
|
89
97
|
| accessibility | ✔ | ✔ | ✔ | ✔ |
|
|
90
98
|
| tokensUsed | — | — | ✔ | ✔ |
|
|
@@ -105,7 +113,7 @@ The manifest stores pointers + per-surface fingerprints, never content:
|
|
|
105
113
|
"fingerprint": "<canonical fingerprint at last render>",
|
|
106
114
|
"surfaces": {
|
|
107
115
|
"figmaDescription": { "src": "<fp>", "render": "<hash of description text>" },
|
|
108
|
-
"docCard": { "src": "<fp>", "render": "<hash of card content>" },
|
|
116
|
+
"docCard": { "src": "<fp>", "render": "<hash of card content>", "renderer": "4" },
|
|
109
117
|
"storybookMdx": { "src": "<fp>", "render": "<hash of mdx file>", "file": "packages/ui/src/Button/Button.mdx" }
|
|
110
118
|
}
|
|
111
119
|
}
|
|
@@ -116,6 +124,11 @@ The manifest stores pointers + per-surface fingerprints, never content:
|
|
|
116
124
|
- `render` — a hash of the surface's rendered content at render time (detects
|
|
117
125
|
**edited**, for surfaces the tooling can re-read).
|
|
118
126
|
- `file` — repo-relative path for code surfaces so `docs:check` can re-read them.
|
|
127
|
+
- `renderer` — (docCard only) the layout version of the builder that last
|
|
128
|
+
rendered the card: `DOC_CARD_RENDERER_VERSION` in `scripts/lib/doc-card-plan.mjs`,
|
|
129
|
+
currently `"4"`. Additive and optional — absence means the card predates the
|
|
130
|
+
versioned builder. Stamped from the builder's returned summary, never by
|
|
131
|
+
re-reading the card.
|
|
119
132
|
|
|
120
133
|
## Drift + reconciliation contract
|
|
121
134
|
|
|
@@ -123,6 +136,11 @@ The manifest stores pointers + per-surface fingerprints, never content:
|
|
|
123
136
|
- **canonical-changed** — the `.doc.json` fingerprint ≠ `doc.fingerprint`.
|
|
124
137
|
- **stale** — `surface.src` ≠ current canonical fingerprint.
|
|
125
138
|
- **edited** — a re-readable surface's current content hash ≠ `surface.render`.
|
|
139
|
+
- **layout-upgrade-available** — informational, never failing, docCard only:
|
|
140
|
+
`surfaces.docCard.renderer` is missing or lower than the current
|
|
141
|
+
`DOC_CARD_RENDERER_VERSION`. The card's content is not in drift — its layout
|
|
142
|
+
predates the current builder. Re-render on next touch (no unprompted Figma
|
|
143
|
+
writes; untouched brownfield cards must not generate a standing warning wall).
|
|
126
144
|
- **missing-surface** — a repo surface that declares a `file` which is now gone.
|
|
127
145
|
Failing, and distinct from `edit-unverified`: the surface *was* re-readable and
|
|
128
146
|
its rendered output has been deleted, not merely unreadable this run.
|