@radicool/throughline 0.25.0 → 0.27.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 -4
- package/adapters/codex/AGENTS.md +2 -0
- package/adapters/codex/prompts/component-builder.md +5 -3
- package/adapters/codex/prompts/compose-code.md +78 -0
- package/adapters/codex/prompts/compose-figma.md +59 -0
- package/adapters/codex/prompts/document-component.md +3 -2
- package/adapters/cursor/.cursor/commands/compose-code.md +78 -0
- package/adapters/cursor/.cursor/commands/compose-figma.md +59 -0
- package/adapters/cursor/.cursor/commands/document-component.md +3 -2
- package/adapters/cursor/.cursor/rules/component-builder.mdc +5 -3
- package/adapters/generic/AGENTS.md +2 -0
- package/adapters/generic/commands/compose-code.md +78 -0
- package/adapters/generic/commands/compose-figma.md +59 -0
- package/adapters/generic/commands/document-component.md +3 -2
- package/adapters/generic/skills/component-builder/SKILL.md +5 -3
- package/package.json +1 -1
- package/references/doc-card-builder.md +62 -15
- package/references/figma-adherence.md +21 -0
- package/references/figma-compose.md +896 -0
- package/scripts/README.md +8 -4
- package/scripts/build-doc-card-builder.mjs +16 -0
- package/scripts/build-figma-checks.mjs +89 -2
- package/scripts/compose-code.mjs +271 -0
- package/scripts/doc-card-payload.mjs +115 -0
- package/scripts/install.mjs +5 -3
- package/scripts/lib/doc-card-plan.mjs +37 -0
- package/scripts/lib/doc-card-render.figma.js +9 -15
- package/scripts/lib/figma-adherence-read.figma.js +21 -0
- package/scripts/lib/figma-compose.figma.js +326 -0
- package/scripts/lib/figma-compose.mjs +317 -0
- package/scripts/lib/fixtures/figma-compose/casing-and-suffix.json +8 -0
- package/scripts/lib/fixtures/figma-compose/fill-in-unlaid-slot.json +7 -0
- package/scripts/lib/fixtures/figma-compose/hug-on-fixed-component.json +34 -0
- package/scripts/lib/fixtures/figma-compose/inventory.json +295 -0
- package/scripts/lib/fixtures/figma-compose/many-errors.json +8 -0
- package/scripts/lib/fixtures/figma-compose/missing-component.json +7 -0
- package/scripts/lib/fixtures/figma-compose/name-taken.json +6 -0
- package/scripts/lib/fixtures/figma-compose/padding-sides.json +23 -0
- package/scripts/lib/fixtures/figma-compose/radius-kind.json +27 -0
- package/scripts/lib/fixtures/figma-compose/raw-number.json +5 -0
- package/scripts/lib/fixtures/figma-compose/sign-in-ok.json +16 -0
- package/scripts/lib/fixtures/figma-compose/slot-ok.json +9 -0
- package/scripts/lib/fixtures/figma-compose/unknown-prop-and-option.json +7 -0
- package/scripts/lib/fixtures/figma-compose/wrong-kind.json +5 -0
package/README.md
CHANGED
|
@@ -73,7 +73,7 @@ Everything above was created during a single working session and synced directly
|
|
|
73
73
|
|
|
74
74
|
| | |
|
|
75
75
|
|---|---|
|
|
76
|
-
| **A supported agent** | Required — [Claude Code](https://docs.claude.com/en/docs/claude-code) (native plugin), or **Cursor**, **Codex**, or any **AGENTS.md**-aware agent via `npx @radicool/throughline@0.
|
|
76
|
+
| **A supported agent** | Required — [Claude Code](https://docs.claude.com/en/docs/claude-code) (native plugin), or **Cursor**, **Codex**, or any **AGENTS.md**-aware agent via `npx @radicool/throughline@0.27.0 init`. |
|
|
77
77
|
| **Figma** | Required, **desktop app** (the browser version causes connection errors). **Professional plan or higher recommended** — multi-mode variables (Light/Dark, brand themes) need it. |
|
|
78
78
|
| **Figma access token** | Optional — only for the few Figma calls the Desktop Bridge can't make, like reading a published library. Without it, you work through the bridge alone. The setup skill walks you through it; your token stays yours and is never shared in chat. |
|
|
79
79
|
| **GitHub** (or similar) | Optional — only when you're ready to graduate to a real remote repo with PRs and CI. |
|
|
@@ -109,6 +109,10 @@ This is the reliable entry point — it runs environment setup first, ahead of a
|
|
|
109
109
|
|
|
110
110
|
Already have screens or components in Figma? `/throughline:check-figma` checks them against the system without touching the file: it flags a component someone detached, and a colour, gap, padding or radius that's hardcoded when a token already has that value. It also runs the state, focus-ring and focus-contrast checks over the components already in your library.
|
|
111
111
|
|
|
112
|
+
Need a new screen? `/throughline:compose-figma` builds it in Figma from your own components and tokens, every value bound. If the screen needs something your system doesn't have, it says so instead of drawing a lookalike, and it runs the same check before handing the screen over.
|
|
113
|
+
|
|
114
|
+
Want it in code instead? `/throughline:compose-code` writes the screen as one React file in your app, using only your components and your tokens. It checks the plan before writing a line, reports any component you don't have rather than building one, and gates the file before handing it over.
|
|
115
|
+
|
|
112
116
|
Update anytime with `/plugin marketplace update throughline-marketplace`.
|
|
113
117
|
|
|
114
118
|
#### Cursor, Codex, or a generic AGENTS.md agent
|
|
@@ -116,9 +120,9 @@ Update anytime with `/plugin marketplace update throughline-marketplace`.
|
|
|
116
120
|
Run the installer in your project — it stamps in the skills, the reference docs, the scripts, and the Figma MCP config for your tool:
|
|
117
121
|
|
|
118
122
|
```
|
|
119
|
-
npx @radicool/throughline@0.
|
|
120
|
-
npx @radicool/throughline@0.
|
|
121
|
-
npx @radicool/throughline@0.
|
|
123
|
+
npx @radicool/throughline@0.27.0 init --target=cursor # → .cursor/rules + .cursor/mcp.json
|
|
124
|
+
npx @radicool/throughline@0.27.0 init --target=codex # → prompts/ + AGENTS.md index + codex-mcp.toml
|
|
125
|
+
npx @radicool/throughline@0.27.0 init --target=generic # → skills/ + AGENTS.md index
|
|
122
126
|
```
|
|
123
127
|
|
|
124
128
|
It's safe to re-run (it merges `AGENTS.md` and `.cursor/mcp.json` non-destructively) and stages everything the skills read into `.throughline/`. Then open the `figma-environment-setup` skill/rule/prompt for your tool to begin. For Codex, add the printed `codex-mcp.toml` block to your Codex config to enable Figma access.
|
package/adapters/codex/AGENTS.md
CHANGED
|
@@ -20,6 +20,8 @@ ThroughLine builds a design system end to end. Load the matching prompt for the
|
|
|
20
20
|
## ThroughLine commands
|
|
21
21
|
|
|
22
22
|
- `check-figma` — Check what's already in Figma against the design system, read-only — screens for detached components and raw values a token has, and existing component sets for their states, focus ring and focus contrast. → load `prompts/check-figma.md`.
|
|
23
|
+
- `compose-code` — Compose a screen in code from the design system's own components and tokens — plan checked before writing, every value a token, gated before it's handed over. → load `prompts/compose-code.md`.
|
|
24
|
+
- `compose-figma` — Compose a screen in Figma from the design system's own components, variables and text styles — every value bound, nothing invented, gated before it's handed over. → load `prompts/compose-figma.md`.
|
|
23
25
|
- `design-system-status` — Show a plain-language summary of the current design system state — what's set up, what's not, and sensible next steps — read from design-system.json. → load `prompts/design-system-status.md`.
|
|
24
26
|
- `document-component` — Author, refresh, or reconcile the usage documentation for one existing component — draft its canonical doc record from four sources, project it to Figma, the doc card, and code, and resolve any drift via a reviewable per-item choice. → load `prompts/document-component.md`.
|
|
25
27
|
- `new-component` — Build a single new component end to end — in Figma, then sync any new tokens, then build its code component and stories — with a confirmation between each stage. → load `prompts/new-component.md`.
|
|
@@ -327,9 +327,11 @@ reference register, not this skill's guide voice.
|
|
|
327
327
|
always last.
|
|
328
328
|
- **Doc card body.** Render the card's `Usage` band with the canonical builder
|
|
329
329
|
snippet in `.throughline/references/doc-card-builder.md` (via
|
|
330
|
-
`figma_execute` with an explicit `timeout`, one card per call):
|
|
331
|
-
|
|
332
|
-
the
|
|
330
|
+
`figma_execute` with an explicit `timeout`, one card per call): assemble the
|
|
331
|
+
call with `node .throughline/scripts/doc-card-payload.mjs <record> <cardNodeId>`
|
|
332
|
+
(it fills the RECORD/CANONICAL_FP slots and resolves the nine semantic
|
|
333
|
+
variables and `Body/Default` per that file's call contract), run it, check
|
|
334
|
+
`summary.renderHash` against the `expectedRenderHash` it printed, and
|
|
333
335
|
verify the returned summary (`rowsRendered`, `blocksCreated`, `cardWidth`) —
|
|
334
336
|
not a screenshot. The builder creates the `Doc Fingerprint` node itself and
|
|
335
337
|
is the only thing that may build the usage body — never hand-assemble it.
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
Compose the screen the user asked for as one React file in their app, from what
|
|
2
|
+
the design system already has. Use the settings already in `design-system.json`
|
|
3
|
+
rather than re-asking them. Scale explanation to `user.codingLevel`.
|
|
4
|
+
|
|
5
|
+
1. **Know the framework.** Read `project.uiFramework` from `design-system.json`.
|
|
6
|
+
Composing in code covers `shadcn` and `tailwind`. For anything else, stop and
|
|
7
|
+
say composing in code doesn't cover that framework yet.
|
|
8
|
+
2. **Find the gate settings.** Search the repo's `package.json` files (not under
|
|
9
|
+
`node_modules`) for an `adherence:check` script. If one exists, take its
|
|
10
|
+
`--system`, `--package` and every `--tokens`, each resolved against the
|
|
11
|
+
directory of the `package.json` that holds it. Otherwise ask the user for the
|
|
12
|
+
package specifier the app imports the system from and the token source files,
|
|
13
|
+
and use the repo root as `--system`. Pass every token file: a system whose
|
|
14
|
+
values span modes has one per mode.
|
|
15
|
+
3. **Know the target.** Unless the user named it, ask for the screen's name and
|
|
16
|
+
the file path to write it to, inside the app. Write `.tsx`, or `.jsx` when the
|
|
17
|
+
app has no TypeScript.
|
|
18
|
+
4. **Read what exists.** Run
|
|
19
|
+
`node .throughline/scripts/compose-code.mjs inventory --system <dir> --package <spec>`.
|
|
20
|
+
Its components, with their variant axes, values, states, `whenToUse` and
|
|
21
|
+
`whenNotToUse`, are the only components the screen may use. Read a listed
|
|
22
|
+
component's own source for its prop names and exported sub-parts
|
|
23
|
+
(`CardHeader`); the inventory records neither. Find it by resolving the
|
|
24
|
+
package specifier: a workspace package in a monorepo, or the app's
|
|
25
|
+
`node_modules` otherwise. Token variable names come from
|
|
26
|
+
the system's generated CSS (the file its styles import), and the utilities
|
|
27
|
+
from its Tailwind preset; read both.
|
|
28
|
+
5. **Plan.** Write the plan as JSON to a scratch file:
|
|
29
|
+
`{ "screen", "file", "components": [{ "name", "variants": { "<axis>": "<value>" } }] }`,
|
|
30
|
+
one entry per component the screen uses, with the variant values it sets. A
|
|
31
|
+
sub-part (`CardHeader`) comes with its owner (`Card`) and needs no entry. When
|
|
32
|
+
the request needs a component the inventory doesn't have, say so before
|
|
33
|
+
writing and ask: leave it out, use a named existing component instead, or stop.
|
|
34
|
+
The `nearest` names are matched on spelling; suggest the alternative that fits
|
|
35
|
+
by `whenToUse` instead when one does. Never build a lookalike. An icon, or
|
|
36
|
+
anything else the system's package doesn't export, is a gap in the same way:
|
|
37
|
+
the screen imports only from the package and React.
|
|
38
|
+
6. **Check the plan.** Run the script with `check --system <dir> --package <spec> --plan <plan file>`
|
|
39
|
+
from the repo root. If it returns errors, nothing has been written: fix the
|
|
40
|
+
plan (a `missing-component` error goes back to the user as in step 5) and check
|
|
41
|
+
again. A `name-taken` error means the file at that path wasn't composed for
|
|
42
|
+
this screen: ask for another path, or for the user to move that file. A
|
|
43
|
+
re-run replaces an earlier composed file only when the screen name matches
|
|
44
|
+
its marker exactly, so reuse the name as written. Write
|
|
45
|
+
the variant values in the casing the returned plan uses.
|
|
46
|
+
7. **Write.** Put the marker `// Composed by throughline: <screen>.` on the first
|
|
47
|
+
line, or on the second after a `'use client'` directive. Import components only
|
|
48
|
+
from the package specifier. Plain elements carry layout only (flex, grid, gap,
|
|
49
|
+
padding, sizing); visible text uses semantic elements (`h1`, `p`, `label`);
|
|
50
|
+
everything the user operates is a system component from the plan (a link may
|
|
51
|
+
be a plain `<a>`). Write colour, spacing, sizing, type size and font weight
|
|
52
|
+
only as token variables
|
|
53
|
+
(`gap-[var(--space-gap-md)]`, `style={{ padding: 'var(--space-4)' }}`) or the
|
|
54
|
+
utilities the system's preset generates from tokens (`bg-primary`,
|
|
55
|
+
`rounded-md`). Never a raw value, and never Tailwind's default scale
|
|
56
|
+
(`gap-4`, `text-lg`, `font-semibold`). Percentages, viewport units,
|
|
57
|
+
fractions (`w-1/2`) and keywords (`w-full`) are layout and fine. The gate
|
|
58
|
+
reads class names anywhere in the file, so visible copy that spells one
|
|
59
|
+
(`text-sm`) fails too; reword the copy rather than the rule. The gate can't
|
|
60
|
+
see a lookalike built from plain elements (a `div` with `role="switch"`), so
|
|
61
|
+
that one is yours to refuse. A size no token holds (a 400px card) can't be bound:
|
|
62
|
+
use a fraction or a keyword and say so in the report. Handlers are stubs; data and state are the app's.
|
|
63
|
+
8. **Gate.** Run the script with
|
|
64
|
+
`gate --system <dir> --package <spec> --plan <plan file> --file <screen file>`,
|
|
65
|
+
with `--tokens <file>` repeated once per token file.
|
|
66
|
+
On a failure, fix the file and run it again, up to three attempts in all. If
|
|
67
|
+
the third still fails, stop: the file stays where it is, marked, and the
|
|
68
|
+
report lists every failure and says a re-run replaces it. Never change the
|
|
69
|
+
plan or skip a rule to make it pass.
|
|
70
|
+
9. **Report.** The file's path, whether it replaced an earlier composed one, the
|
|
71
|
+
gate's counts, every gap (each component asked for that doesn't exist, with the
|
|
72
|
+
nearest names the script offered, and what was left out because of it), and
|
|
73
|
+
how to mount the screen where the app picks its screens (its router or entry).
|
|
74
|
+
Don't edit it.
|
|
75
|
+
|
|
76
|
+
Never edit a component, a token or the app's routing. If the screen can't be
|
|
77
|
+
built from what the system has, the gap is the finding.
|
|
78
|
+
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
Compose the screen the user asked for in Figma, from what the file already has.
|
|
2
|
+
Use the settings already in `design-system.json` (`figma.fileKey`) rather than
|
|
3
|
+
re-asking them. Scale explanation to `user.codingLevel`.
|
|
4
|
+
|
|
5
|
+
1. **Know the file.** Read `figma.fileKey` from `design-system.json`. If it's
|
|
6
|
+
absent, stop and ask which file to compose in.
|
|
7
|
+
2. **Confirm the active file.** Run the preflight in
|
|
8
|
+
`.throughline/references/figma-scripting.md` ("confirm the *active*
|
|
9
|
+
file is your target") against that fileKey, and pin it with `figma_navigate`
|
|
10
|
+
(`lock: true`) for the run. Unpin when done.
|
|
11
|
+
3. **Read what exists.** Unless the user named them, ask which page holds the
|
|
12
|
+
component sets and which page the screen goes on (it's created if missing). Run
|
|
13
|
+
the snippet in `.throughline/references/figma-compose.md` verbatim, called
|
|
14
|
+
as its "How to call it" section says (`MODE` and `SPEC` declared above it,
|
|
15
|
+
`return await runCompose(MODE, SPEC);` below it), with `MODE = 'inventory'` and
|
|
16
|
+
`SPEC = { componentsPage }`. If the plan will set an instance-swap property (an
|
|
17
|
+
icon, say), ask which page holds the swap targets and run `inventory` again with
|
|
18
|
+
`iconsPage`.
|
|
19
|
+
4. **Plan.** Write the screen description (its shape is the `DESCRIPTION` comment
|
|
20
|
+
in the snippet, at the top of the resolver) using only names from the
|
|
21
|
+
inventory's summary: component sets and their properties and options, variables
|
|
22
|
+
by kind, text styles, modes. Leave `sizing` off an instance unless it should
|
|
23
|
+
fill; `hug` works only on a set whose summary says `autoLayout: true`. Frames
|
|
24
|
+
carry layout only (auto layout, gap, padding, fill, stroke, radius); everything
|
|
25
|
+
the user sees is a component instance or styled text. When the request needs a
|
|
26
|
+
component the inventory doesn't have, say so before building and ask: leave it
|
|
27
|
+
out, use a named existing component instead, or stop. Never draw a lookalike
|
|
28
|
+
from frames.
|
|
29
|
+
5. **Build.** Run the snippet with `MODE = 'build'` and
|
|
30
|
+
`SPEC = { componentsPage, iconsPage, description, fileKey }`. If it returns
|
|
31
|
+
errors, nothing was written: fix the description (a `missing-component` error
|
|
32
|
+
goes back to the user as in step 4) and build again. A `name-taken` error on
|
|
33
|
+
`<screen>` means a screen a person made already has that name: ask for another
|
|
34
|
+
name. On `WIP: <screen>` it means an unmarked frame holds the working name: ask
|
|
35
|
+
the user to rename or remove it. If the call throws instead, the build rolled
|
|
36
|
+
itself back and nothing was written: stop, and report the error as a composer
|
|
37
|
+
bug rather than reworking the screen around it.
|
|
38
|
+
6. **Gate.** Run the screen gate in
|
|
39
|
+
`.throughline/references/figma-adherence.md` verbatim with
|
|
40
|
+
`TARGET = { page, screens: ['WIP: <screen>'], fileKey }` and `SKIP = []`. If it
|
|
41
|
+
fails, stop: report its failures as a composer bug, with their links, and leave
|
|
42
|
+
the `WIP:` frame for inspection. Don't change the description to make it pass.
|
|
43
|
+
Remove that frame with `MODE = 'discard'` and `SPEC = { page, screen }` only
|
|
44
|
+
when the user asks.
|
|
45
|
+
7. **Finalize.** Run the snippet with `MODE = 'finalize'` and
|
|
46
|
+
`SPEC = { page, screen, fileKey }`. It replaces an earlier screen of that name
|
|
47
|
+
only if throughline composed it.
|
|
48
|
+
8. **Review.** Dispatch the `reviewer` agent in Figma-visual mode with the screen's
|
|
49
|
+
node id (from finalize), the fileKey, the project's working directory (where
|
|
50
|
+
`design-system.json` is) and the user's request as its spec, unless the host
|
|
51
|
+
can't dispatch agents, in which case screenshot the screen yourself and say so.
|
|
52
|
+
9. **Report.** The screen's link, whether it replaced an earlier one, the gate's
|
|
53
|
+
counts, the reviewer's verdict, and every gap: each component that was asked
|
|
54
|
+
for and doesn't exist, with the nearest names the script offered, and anything
|
|
55
|
+
left out of the request because of it.
|
|
56
|
+
|
|
57
|
+
Never edit a component, a variable or a text style, and never write a raw value.
|
|
58
|
+
If the screen can't be built from what the system has, the gap is the finding.
|
|
59
|
+
|
|
@@ -24,8 +24,9 @@ Ask which component to document (e.g. "Button"), then:
|
|
|
24
24
|
2. **Project it.** Write `design-system/docs/components/<Name>.doc.json`, set the
|
|
25
25
|
Figma component `description`, rebuild the doc card's `Usage` band with the
|
|
26
26
|
canonical builder (`.throughline/references/doc-card-builder.md` —
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
assemble the call with `node .throughline/scripts/doc-card-payload.mjs`,
|
|
28
|
+
check the returned `renderHash` against the one it printed, verify the
|
|
29
|
+
returned summary and stamp `surfaces.docCard.{src,render,renderer}` from it), and (if the repo/code side exists) render MDX/JSDoc and run
|
|
29
30
|
`docs:digest` per the `storybook-chromatic-builder` render step.
|
|
30
31
|
Before the Figma writes, run the active-file preflight in
|
|
31
32
|
`.throughline/references/figma-scripting.md` — this command writes
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
Compose the screen the user asked for as one React file in their app, from what
|
|
2
|
+
the design system already has. Use the settings already in `design-system.json`
|
|
3
|
+
rather than re-asking them. Scale explanation to `user.codingLevel`.
|
|
4
|
+
|
|
5
|
+
1. **Know the framework.** Read `project.uiFramework` from `design-system.json`.
|
|
6
|
+
Composing in code covers `shadcn` and `tailwind`. For anything else, stop and
|
|
7
|
+
say composing in code doesn't cover that framework yet.
|
|
8
|
+
2. **Find the gate settings.** Search the repo's `package.json` files (not under
|
|
9
|
+
`node_modules`) for an `adherence:check` script. If one exists, take its
|
|
10
|
+
`--system`, `--package` and every `--tokens`, each resolved against the
|
|
11
|
+
directory of the `package.json` that holds it. Otherwise ask the user for the
|
|
12
|
+
package specifier the app imports the system from and the token source files,
|
|
13
|
+
and use the repo root as `--system`. Pass every token file: a system whose
|
|
14
|
+
values span modes has one per mode.
|
|
15
|
+
3. **Know the target.** Unless the user named it, ask for the screen's name and
|
|
16
|
+
the file path to write it to, inside the app. Write `.tsx`, or `.jsx` when the
|
|
17
|
+
app has no TypeScript.
|
|
18
|
+
4. **Read what exists.** Run
|
|
19
|
+
`node .throughline/scripts/compose-code.mjs inventory --system <dir> --package <spec>`.
|
|
20
|
+
Its components, with their variant axes, values, states, `whenToUse` and
|
|
21
|
+
`whenNotToUse`, are the only components the screen may use. Read a listed
|
|
22
|
+
component's own source for its prop names and exported sub-parts
|
|
23
|
+
(`CardHeader`); the inventory records neither. Find it by resolving the
|
|
24
|
+
package specifier: a workspace package in a monorepo, or the app's
|
|
25
|
+
`node_modules` otherwise. Token variable names come from
|
|
26
|
+
the system's generated CSS (the file its styles import), and the utilities
|
|
27
|
+
from its Tailwind preset; read both.
|
|
28
|
+
5. **Plan.** Write the plan as JSON to a scratch file:
|
|
29
|
+
`{ "screen", "file", "components": [{ "name", "variants": { "<axis>": "<value>" } }] }`,
|
|
30
|
+
one entry per component the screen uses, with the variant values it sets. A
|
|
31
|
+
sub-part (`CardHeader`) comes with its owner (`Card`) and needs no entry. When
|
|
32
|
+
the request needs a component the inventory doesn't have, say so before
|
|
33
|
+
writing and ask: leave it out, use a named existing component instead, or stop.
|
|
34
|
+
The `nearest` names are matched on spelling; suggest the alternative that fits
|
|
35
|
+
by `whenToUse` instead when one does. Never build a lookalike. An icon, or
|
|
36
|
+
anything else the system's package doesn't export, is a gap in the same way:
|
|
37
|
+
the screen imports only from the package and React.
|
|
38
|
+
6. **Check the plan.** Run the script with `check --system <dir> --package <spec> --plan <plan file>`
|
|
39
|
+
from the repo root. If it returns errors, nothing has been written: fix the
|
|
40
|
+
plan (a `missing-component` error goes back to the user as in step 5) and check
|
|
41
|
+
again. A `name-taken` error means the file at that path wasn't composed for
|
|
42
|
+
this screen: ask for another path, or for the user to move that file. A
|
|
43
|
+
re-run replaces an earlier composed file only when the screen name matches
|
|
44
|
+
its marker exactly, so reuse the name as written. Write
|
|
45
|
+
the variant values in the casing the returned plan uses.
|
|
46
|
+
7. **Write.** Put the marker `// Composed by throughline: <screen>.` on the first
|
|
47
|
+
line, or on the second after a `'use client'` directive. Import components only
|
|
48
|
+
from the package specifier. Plain elements carry layout only (flex, grid, gap,
|
|
49
|
+
padding, sizing); visible text uses semantic elements (`h1`, `p`, `label`);
|
|
50
|
+
everything the user operates is a system component from the plan (a link may
|
|
51
|
+
be a plain `<a>`). Write colour, spacing, sizing, type size and font weight
|
|
52
|
+
only as token variables
|
|
53
|
+
(`gap-[var(--space-gap-md)]`, `style={{ padding: 'var(--space-4)' }}`) or the
|
|
54
|
+
utilities the system's preset generates from tokens (`bg-primary`,
|
|
55
|
+
`rounded-md`). Never a raw value, and never Tailwind's default scale
|
|
56
|
+
(`gap-4`, `text-lg`, `font-semibold`). Percentages, viewport units,
|
|
57
|
+
fractions (`w-1/2`) and keywords (`w-full`) are layout and fine. The gate
|
|
58
|
+
reads class names anywhere in the file, so visible copy that spells one
|
|
59
|
+
(`text-sm`) fails too; reword the copy rather than the rule. The gate can't
|
|
60
|
+
see a lookalike built from plain elements (a `div` with `role="switch"`), so
|
|
61
|
+
that one is yours to refuse. A size no token holds (a 400px card) can't be bound:
|
|
62
|
+
use a fraction or a keyword and say so in the report. Handlers are stubs; data and state are the app's.
|
|
63
|
+
8. **Gate.** Run the script with
|
|
64
|
+
`gate --system <dir> --package <spec> --plan <plan file> --file <screen file>`,
|
|
65
|
+
with `--tokens <file>` repeated once per token file.
|
|
66
|
+
On a failure, fix the file and run it again, up to three attempts in all. If
|
|
67
|
+
the third still fails, stop: the file stays where it is, marked, and the
|
|
68
|
+
report lists every failure and says a re-run replaces it. Never change the
|
|
69
|
+
plan or skip a rule to make it pass.
|
|
70
|
+
9. **Report.** The file's path, whether it replaced an earlier composed one, the
|
|
71
|
+
gate's counts, every gap (each component asked for that doesn't exist, with the
|
|
72
|
+
nearest names the script offered, and what was left out because of it), and
|
|
73
|
+
how to mount the screen where the app picks its screens (its router or entry).
|
|
74
|
+
Don't edit it.
|
|
75
|
+
|
|
76
|
+
Never edit a component, a token or the app's routing. If the screen can't be
|
|
77
|
+
built from what the system has, the gap is the finding.
|
|
78
|
+
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
Compose the screen the user asked for in Figma, from what the file already has.
|
|
2
|
+
Use the settings already in `design-system.json` (`figma.fileKey`) rather than
|
|
3
|
+
re-asking them. Scale explanation to `user.codingLevel`.
|
|
4
|
+
|
|
5
|
+
1. **Know the file.** Read `figma.fileKey` from `design-system.json`. If it's
|
|
6
|
+
absent, stop and ask which file to compose in.
|
|
7
|
+
2. **Confirm the active file.** Run the preflight in
|
|
8
|
+
`.throughline/references/figma-scripting.md` ("confirm the *active*
|
|
9
|
+
file is your target") against that fileKey, and pin it with `figma_navigate`
|
|
10
|
+
(`lock: true`) for the run. Unpin when done.
|
|
11
|
+
3. **Read what exists.** Unless the user named them, ask which page holds the
|
|
12
|
+
component sets and which page the screen goes on (it's created if missing). Run
|
|
13
|
+
the snippet in `.throughline/references/figma-compose.md` verbatim, called
|
|
14
|
+
as its "How to call it" section says (`MODE` and `SPEC` declared above it,
|
|
15
|
+
`return await runCompose(MODE, SPEC);` below it), with `MODE = 'inventory'` and
|
|
16
|
+
`SPEC = { componentsPage }`. If the plan will set an instance-swap property (an
|
|
17
|
+
icon, say), ask which page holds the swap targets and run `inventory` again with
|
|
18
|
+
`iconsPage`.
|
|
19
|
+
4. **Plan.** Write the screen description (its shape is the `DESCRIPTION` comment
|
|
20
|
+
in the snippet, at the top of the resolver) using only names from the
|
|
21
|
+
inventory's summary: component sets and their properties and options, variables
|
|
22
|
+
by kind, text styles, modes. Leave `sizing` off an instance unless it should
|
|
23
|
+
fill; `hug` works only on a set whose summary says `autoLayout: true`. Frames
|
|
24
|
+
carry layout only (auto layout, gap, padding, fill, stroke, radius); everything
|
|
25
|
+
the user sees is a component instance or styled text. When the request needs a
|
|
26
|
+
component the inventory doesn't have, say so before building and ask: leave it
|
|
27
|
+
out, use a named existing component instead, or stop. Never draw a lookalike
|
|
28
|
+
from frames.
|
|
29
|
+
5. **Build.** Run the snippet with `MODE = 'build'` and
|
|
30
|
+
`SPEC = { componentsPage, iconsPage, description, fileKey }`. If it returns
|
|
31
|
+
errors, nothing was written: fix the description (a `missing-component` error
|
|
32
|
+
goes back to the user as in step 4) and build again. A `name-taken` error on
|
|
33
|
+
`<screen>` means a screen a person made already has that name: ask for another
|
|
34
|
+
name. On `WIP: <screen>` it means an unmarked frame holds the working name: ask
|
|
35
|
+
the user to rename or remove it. If the call throws instead, the build rolled
|
|
36
|
+
itself back and nothing was written: stop, and report the error as a composer
|
|
37
|
+
bug rather than reworking the screen around it.
|
|
38
|
+
6. **Gate.** Run the screen gate in
|
|
39
|
+
`.throughline/references/figma-adherence.md` verbatim with
|
|
40
|
+
`TARGET = { page, screens: ['WIP: <screen>'], fileKey }` and `SKIP = []`. If it
|
|
41
|
+
fails, stop: report its failures as a composer bug, with their links, and leave
|
|
42
|
+
the `WIP:` frame for inspection. Don't change the description to make it pass.
|
|
43
|
+
Remove that frame with `MODE = 'discard'` and `SPEC = { page, screen }` only
|
|
44
|
+
when the user asks.
|
|
45
|
+
7. **Finalize.** Run the snippet with `MODE = 'finalize'` and
|
|
46
|
+
`SPEC = { page, screen, fileKey }`. It replaces an earlier screen of that name
|
|
47
|
+
only if throughline composed it.
|
|
48
|
+
8. **Review.** Dispatch the `reviewer` agent in Figma-visual mode with the screen's
|
|
49
|
+
node id (from finalize), the fileKey, the project's working directory (where
|
|
50
|
+
`design-system.json` is) and the user's request as its spec, unless the host
|
|
51
|
+
can't dispatch agents, in which case screenshot the screen yourself and say so.
|
|
52
|
+
9. **Report.** The screen's link, whether it replaced an earlier one, the gate's
|
|
53
|
+
counts, the reviewer's verdict, and every gap: each component that was asked
|
|
54
|
+
for and doesn't exist, with the nearest names the script offered, and anything
|
|
55
|
+
left out of the request because of it.
|
|
56
|
+
|
|
57
|
+
Never edit a component, a variable or a text style, and never write a raw value.
|
|
58
|
+
If the screen can't be built from what the system has, the gap is the finding.
|
|
59
|
+
|
|
@@ -24,8 +24,9 @@ Ask which component to document (e.g. "Button"), then:
|
|
|
24
24
|
2. **Project it.** Write `design-system/docs/components/<Name>.doc.json`, set the
|
|
25
25
|
Figma component `description`, rebuild the doc card's `Usage` band with the
|
|
26
26
|
canonical builder (`.throughline/references/doc-card-builder.md` —
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
assemble the call with `node .throughline/scripts/doc-card-payload.mjs`,
|
|
28
|
+
check the returned `renderHash` against the one it printed, verify the
|
|
29
|
+
returned summary and stamp `surfaces.docCard.{src,render,renderer}` from it), and (if the repo/code side exists) render MDX/JSDoc and run
|
|
29
30
|
`docs:digest` per the `storybook-chromatic-builder` render step.
|
|
30
31
|
Before the Figma writes, run the active-file preflight in
|
|
31
32
|
`.throughline/references/figma-scripting.md` — this command writes
|
|
@@ -331,9 +331,11 @@ reference register, not this skill's guide voice.
|
|
|
331
331
|
always last.
|
|
332
332
|
- **Doc card body.** Render the card's `Usage` band with the canonical builder
|
|
333
333
|
snippet in `.throughline/references/doc-card-builder.md` (via
|
|
334
|
-
`figma_execute` with an explicit `timeout`, one card per call):
|
|
335
|
-
|
|
336
|
-
the
|
|
334
|
+
`figma_execute` with an explicit `timeout`, one card per call): assemble the
|
|
335
|
+
call with `node .throughline/scripts/doc-card-payload.mjs <record> <cardNodeId>`
|
|
336
|
+
(it fills the RECORD/CANONICAL_FP slots and resolves the nine semantic
|
|
337
|
+
variables and `Body/Default` per that file's call contract), run it, check
|
|
338
|
+
`summary.renderHash` against the `expectedRenderHash` it printed, and
|
|
337
339
|
verify the returned summary (`rowsRendered`, `blocksCreated`, `cardWidth`) —
|
|
338
340
|
not a screenshot. The builder creates the `Doc Fingerprint` node itself and
|
|
339
341
|
is the only thing that may build the usage body — never hand-assemble it.
|
|
@@ -20,6 +20,8 @@ ThroughLine builds a design system end to end. Read the matching skill file for
|
|
|
20
20
|
## ThroughLine commands
|
|
21
21
|
|
|
22
22
|
- `check-figma` — Check what's already in Figma against the design system, read-only — screens for detached components and raw values a token has, and existing component sets for their states, focus ring and focus contrast. → read `commands/check-figma.md`.
|
|
23
|
+
- `compose-code` — Compose a screen in code from the design system's own components and tokens — plan checked before writing, every value a token, gated before it's handed over. → read `commands/compose-code.md`.
|
|
24
|
+
- `compose-figma` — Compose a screen in Figma from the design system's own components, variables and text styles — every value bound, nothing invented, gated before it's handed over. → read `commands/compose-figma.md`.
|
|
23
25
|
- `design-system-status` — Show a plain-language summary of the current design system state — what's set up, what's not, and sensible next steps — read from design-system.json. → read `commands/design-system-status.md`.
|
|
24
26
|
- `document-component` — Author, refresh, or reconcile the usage documentation for one existing component — draft its canonical doc record from four sources, project it to Figma, the doc card, and code, and resolve any drift via a reviewable per-item choice. → read `commands/document-component.md`.
|
|
25
27
|
- `new-component` — Build a single new component end to end — in Figma, then sync any new tokens, then build its code component and stories — with a confirmation between each stage. → read `commands/new-component.md`.
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
Compose the screen the user asked for as one React file in their app, from what
|
|
2
|
+
the design system already has. Use the settings already in `design-system.json`
|
|
3
|
+
rather than re-asking them. Scale explanation to `user.codingLevel`.
|
|
4
|
+
|
|
5
|
+
1. **Know the framework.** Read `project.uiFramework` from `design-system.json`.
|
|
6
|
+
Composing in code covers `shadcn` and `tailwind`. For anything else, stop and
|
|
7
|
+
say composing in code doesn't cover that framework yet.
|
|
8
|
+
2. **Find the gate settings.** Search the repo's `package.json` files (not under
|
|
9
|
+
`node_modules`) for an `adherence:check` script. If one exists, take its
|
|
10
|
+
`--system`, `--package` and every `--tokens`, each resolved against the
|
|
11
|
+
directory of the `package.json` that holds it. Otherwise ask the user for the
|
|
12
|
+
package specifier the app imports the system from and the token source files,
|
|
13
|
+
and use the repo root as `--system`. Pass every token file: a system whose
|
|
14
|
+
values span modes has one per mode.
|
|
15
|
+
3. **Know the target.** Unless the user named it, ask for the screen's name and
|
|
16
|
+
the file path to write it to, inside the app. Write `.tsx`, or `.jsx` when the
|
|
17
|
+
app has no TypeScript.
|
|
18
|
+
4. **Read what exists.** Run
|
|
19
|
+
`node .throughline/scripts/compose-code.mjs inventory --system <dir> --package <spec>`.
|
|
20
|
+
Its components, with their variant axes, values, states, `whenToUse` and
|
|
21
|
+
`whenNotToUse`, are the only components the screen may use. Read a listed
|
|
22
|
+
component's own source for its prop names and exported sub-parts
|
|
23
|
+
(`CardHeader`); the inventory records neither. Find it by resolving the
|
|
24
|
+
package specifier: a workspace package in a monorepo, or the app's
|
|
25
|
+
`node_modules` otherwise. Token variable names come from
|
|
26
|
+
the system's generated CSS (the file its styles import), and the utilities
|
|
27
|
+
from its Tailwind preset; read both.
|
|
28
|
+
5. **Plan.** Write the plan as JSON to a scratch file:
|
|
29
|
+
`{ "screen", "file", "components": [{ "name", "variants": { "<axis>": "<value>" } }] }`,
|
|
30
|
+
one entry per component the screen uses, with the variant values it sets. A
|
|
31
|
+
sub-part (`CardHeader`) comes with its owner (`Card`) and needs no entry. When
|
|
32
|
+
the request needs a component the inventory doesn't have, say so before
|
|
33
|
+
writing and ask: leave it out, use a named existing component instead, or stop.
|
|
34
|
+
The `nearest` names are matched on spelling; suggest the alternative that fits
|
|
35
|
+
by `whenToUse` instead when one does. Never build a lookalike. An icon, or
|
|
36
|
+
anything else the system's package doesn't export, is a gap in the same way:
|
|
37
|
+
the screen imports only from the package and React.
|
|
38
|
+
6. **Check the plan.** Run the script with `check --system <dir> --package <spec> --plan <plan file>`
|
|
39
|
+
from the repo root. If it returns errors, nothing has been written: fix the
|
|
40
|
+
plan (a `missing-component` error goes back to the user as in step 5) and check
|
|
41
|
+
again. A `name-taken` error means the file at that path wasn't composed for
|
|
42
|
+
this screen: ask for another path, or for the user to move that file. A
|
|
43
|
+
re-run replaces an earlier composed file only when the screen name matches
|
|
44
|
+
its marker exactly, so reuse the name as written. Write
|
|
45
|
+
the variant values in the casing the returned plan uses.
|
|
46
|
+
7. **Write.** Put the marker `// Composed by throughline: <screen>.` on the first
|
|
47
|
+
line, or on the second after a `'use client'` directive. Import components only
|
|
48
|
+
from the package specifier. Plain elements carry layout only (flex, grid, gap,
|
|
49
|
+
padding, sizing); visible text uses semantic elements (`h1`, `p`, `label`);
|
|
50
|
+
everything the user operates is a system component from the plan (a link may
|
|
51
|
+
be a plain `<a>`). Write colour, spacing, sizing, type size and font weight
|
|
52
|
+
only as token variables
|
|
53
|
+
(`gap-[var(--space-gap-md)]`, `style={{ padding: 'var(--space-4)' }}`) or the
|
|
54
|
+
utilities the system's preset generates from tokens (`bg-primary`,
|
|
55
|
+
`rounded-md`). Never a raw value, and never Tailwind's default scale
|
|
56
|
+
(`gap-4`, `text-lg`, `font-semibold`). Percentages, viewport units,
|
|
57
|
+
fractions (`w-1/2`) and keywords (`w-full`) are layout and fine. The gate
|
|
58
|
+
reads class names anywhere in the file, so visible copy that spells one
|
|
59
|
+
(`text-sm`) fails too; reword the copy rather than the rule. The gate can't
|
|
60
|
+
see a lookalike built from plain elements (a `div` with `role="switch"`), so
|
|
61
|
+
that one is yours to refuse. A size no token holds (a 400px card) can't be bound:
|
|
62
|
+
use a fraction or a keyword and say so in the report. Handlers are stubs; data and state are the app's.
|
|
63
|
+
8. **Gate.** Run the script with
|
|
64
|
+
`gate --system <dir> --package <spec> --plan <plan file> --file <screen file>`,
|
|
65
|
+
with `--tokens <file>` repeated once per token file.
|
|
66
|
+
On a failure, fix the file and run it again, up to three attempts in all. If
|
|
67
|
+
the third still fails, stop: the file stays where it is, marked, and the
|
|
68
|
+
report lists every failure and says a re-run replaces it. Never change the
|
|
69
|
+
plan or skip a rule to make it pass.
|
|
70
|
+
9. **Report.** The file's path, whether it replaced an earlier composed one, the
|
|
71
|
+
gate's counts, every gap (each component asked for that doesn't exist, with the
|
|
72
|
+
nearest names the script offered, and what was left out because of it), and
|
|
73
|
+
how to mount the screen where the app picks its screens (its router or entry).
|
|
74
|
+
Don't edit it.
|
|
75
|
+
|
|
76
|
+
Never edit a component, a token or the app's routing. If the screen can't be
|
|
77
|
+
built from what the system has, the gap is the finding.
|
|
78
|
+
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
Compose the screen the user asked for in Figma, from what the file already has.
|
|
2
|
+
Use the settings already in `design-system.json` (`figma.fileKey`) rather than
|
|
3
|
+
re-asking them. Scale explanation to `user.codingLevel`.
|
|
4
|
+
|
|
5
|
+
1. **Know the file.** Read `figma.fileKey` from `design-system.json`. If it's
|
|
6
|
+
absent, stop and ask which file to compose in.
|
|
7
|
+
2. **Confirm the active file.** Run the preflight in
|
|
8
|
+
`.throughline/references/figma-scripting.md` ("confirm the *active*
|
|
9
|
+
file is your target") against that fileKey, and pin it with `figma_navigate`
|
|
10
|
+
(`lock: true`) for the run. Unpin when done.
|
|
11
|
+
3. **Read what exists.** Unless the user named them, ask which page holds the
|
|
12
|
+
component sets and which page the screen goes on (it's created if missing). Run
|
|
13
|
+
the snippet in `.throughline/references/figma-compose.md` verbatim, called
|
|
14
|
+
as its "How to call it" section says (`MODE` and `SPEC` declared above it,
|
|
15
|
+
`return await runCompose(MODE, SPEC);` below it), with `MODE = 'inventory'` and
|
|
16
|
+
`SPEC = { componentsPage }`. If the plan will set an instance-swap property (an
|
|
17
|
+
icon, say), ask which page holds the swap targets and run `inventory` again with
|
|
18
|
+
`iconsPage`.
|
|
19
|
+
4. **Plan.** Write the screen description (its shape is the `DESCRIPTION` comment
|
|
20
|
+
in the snippet, at the top of the resolver) using only names from the
|
|
21
|
+
inventory's summary: component sets and their properties and options, variables
|
|
22
|
+
by kind, text styles, modes. Leave `sizing` off an instance unless it should
|
|
23
|
+
fill; `hug` works only on a set whose summary says `autoLayout: true`. Frames
|
|
24
|
+
carry layout only (auto layout, gap, padding, fill, stroke, radius); everything
|
|
25
|
+
the user sees is a component instance or styled text. When the request needs a
|
|
26
|
+
component the inventory doesn't have, say so before building and ask: leave it
|
|
27
|
+
out, use a named existing component instead, or stop. Never draw a lookalike
|
|
28
|
+
from frames.
|
|
29
|
+
5. **Build.** Run the snippet with `MODE = 'build'` and
|
|
30
|
+
`SPEC = { componentsPage, iconsPage, description, fileKey }`. If it returns
|
|
31
|
+
errors, nothing was written: fix the description (a `missing-component` error
|
|
32
|
+
goes back to the user as in step 4) and build again. A `name-taken` error on
|
|
33
|
+
`<screen>` means a screen a person made already has that name: ask for another
|
|
34
|
+
name. On `WIP: <screen>` it means an unmarked frame holds the working name: ask
|
|
35
|
+
the user to rename or remove it. If the call throws instead, the build rolled
|
|
36
|
+
itself back and nothing was written: stop, and report the error as a composer
|
|
37
|
+
bug rather than reworking the screen around it.
|
|
38
|
+
6. **Gate.** Run the screen gate in
|
|
39
|
+
`.throughline/references/figma-adherence.md` verbatim with
|
|
40
|
+
`TARGET = { page, screens: ['WIP: <screen>'], fileKey }` and `SKIP = []`. If it
|
|
41
|
+
fails, stop: report its failures as a composer bug, with their links, and leave
|
|
42
|
+
the `WIP:` frame for inspection. Don't change the description to make it pass.
|
|
43
|
+
Remove that frame with `MODE = 'discard'` and `SPEC = { page, screen }` only
|
|
44
|
+
when the user asks.
|
|
45
|
+
7. **Finalize.** Run the snippet with `MODE = 'finalize'` and
|
|
46
|
+
`SPEC = { page, screen, fileKey }`. It replaces an earlier screen of that name
|
|
47
|
+
only if throughline composed it.
|
|
48
|
+
8. **Review.** Dispatch the `reviewer` agent in Figma-visual mode with the screen's
|
|
49
|
+
node id (from finalize), the fileKey, the project's working directory (where
|
|
50
|
+
`design-system.json` is) and the user's request as its spec, unless the host
|
|
51
|
+
can't dispatch agents, in which case screenshot the screen yourself and say so.
|
|
52
|
+
9. **Report.** The screen's link, whether it replaced an earlier one, the gate's
|
|
53
|
+
counts, the reviewer's verdict, and every gap: each component that was asked
|
|
54
|
+
for and doesn't exist, with the nearest names the script offered, and anything
|
|
55
|
+
left out of the request because of it.
|
|
56
|
+
|
|
57
|
+
Never edit a component, a variable or a text style, and never write a raw value.
|
|
58
|
+
If the screen can't be built from what the system has, the gap is the finding.
|
|
59
|
+
|
|
@@ -24,8 +24,9 @@ Ask which component to document (e.g. "Button"), then:
|
|
|
24
24
|
2. **Project it.** Write `design-system/docs/components/<Name>.doc.json`, set the
|
|
25
25
|
Figma component `description`, rebuild the doc card's `Usage` band with the
|
|
26
26
|
canonical builder (`.throughline/references/doc-card-builder.md` —
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
assemble the call with `node .throughline/scripts/doc-card-payload.mjs`,
|
|
28
|
+
check the returned `renderHash` against the one it printed, verify the
|
|
29
|
+
returned summary and stamp `surfaces.docCard.{src,render,renderer}` from it), and (if the repo/code side exists) render MDX/JSDoc and run
|
|
29
30
|
`docs:digest` per the `storybook-chromatic-builder` render step.
|
|
30
31
|
Before the Figma writes, run the active-file preflight in
|
|
31
32
|
`.throughline/references/figma-scripting.md` — this command writes
|
|
@@ -327,9 +327,11 @@ reference register, not this skill's guide voice.
|
|
|
327
327
|
always last.
|
|
328
328
|
- **Doc card body.** Render the card's `Usage` band with the canonical builder
|
|
329
329
|
snippet in `.throughline/references/doc-card-builder.md` (via
|
|
330
|
-
`figma_execute` with an explicit `timeout`, one card per call):
|
|
331
|
-
|
|
332
|
-
the
|
|
330
|
+
`figma_execute` with an explicit `timeout`, one card per call): assemble the
|
|
331
|
+
call with `node .throughline/scripts/doc-card-payload.mjs <record> <cardNodeId>`
|
|
332
|
+
(it fills the RECORD/CANONICAL_FP slots and resolves the nine semantic
|
|
333
|
+
variables and `Body/Default` per that file's call contract), run it, check
|
|
334
|
+
`summary.renderHash` against the `expectedRenderHash` it printed, and
|
|
333
335
|
verify the returned summary (`rowsRendered`, `blocksCreated`, `cardWidth`) —
|
|
334
336
|
not a screenshot. The builder creates the `Doc Fingerprint` node itself and
|
|
335
337
|
is the only thing that may build the usage body — never hand-assemble it.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@radicool/throughline",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.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": {
|