@radicool/throughline 0.23.0 → 0.25.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 +7 -5
- package/adapters/codex/AGENTS.md +1 -0
- package/adapters/codex/prompts/check-figma.md +41 -0
- package/adapters/codex/prompts/component-builder.md +8 -4
- package/adapters/cursor/.cursor/commands/check-figma.md +41 -0
- package/adapters/cursor/.cursor/rules/component-builder.mdc +8 -4
- package/adapters/generic/AGENTS.md +1 -0
- package/adapters/generic/commands/check-figma.md +41 -0
- package/adapters/generic/skills/component-builder/SKILL.md +8 -4
- package/package.json +1 -1
- package/references/figma-adherence.md +442 -0
- package/references/figma-checks.md +432 -40
- package/references/figma-component-standards.md +8 -0
- package/references/proof-bundle.md +1 -0
- package/scripts/README.md +7 -4
- package/scripts/build-figma-checks.mjs +139 -28
- package/scripts/install.mjs +5 -1
- package/scripts/lib/contrast.mjs +5 -2
- package/scripts/lib/figma-adherence-read.figma.js +207 -0
- package/scripts/lib/figma-adherence.mjs +146 -0
- package/scripts/lib/figma-checks-read.figma.js +68 -14
- package/scripts/lib/figma-checks.mjs +173 -17
- package/scripts/lib/figma-variables-read.figma.js +39 -0
- package/scripts/lib/fixtures/figma-adherence/clean.json +90 -0
- package/scripts/lib/fixtures/figma-adherence/detached-library.json +116 -0
- package/scripts/lib/fixtures/figma-adherence/ds01-gaps.json +84 -0
- package/scripts/lib/fixtures/figma-adherence/inert-all.json +45 -0
- package/scripts/lib/fixtures/figma-adherence/mixed-text.json +61 -0
- package/scripts/lib/fixtures/figma-adherence/nothing-scanned.json +49 -0
- package/scripts/lib/fixtures/figma-adherence/off-scale-gap.json +65 -0
- package/scripts/lib/fixtures/figma-adherence/override-raw.json +72 -0
- package/scripts/lib/fixtures/figma-adherence/padding-raw.json +74 -0
- package/scripts/lib/fixtures/figma-adherence/raw-colour-token.json +70 -0
- package/scripts/lib/fixtures/figma-adherence/root-radius.json +88 -0
- package/scripts/lib/fixtures/figma-adherence/skip-colour.json +86 -0
- package/scripts/lib/fixtures/figma-adherence/zygarden-override-bound.json +85 -0
- package/scripts/lib/fixtures/figma-adherence/zygarden-text-raw.json +208 -0
- package/scripts/lib/fixtures/figma-checks/avatar-not-in-table.json +2 -1
- package/scripts/lib/fixtures/figma-checks/button-ios-swift-skipped.json +2 -1
- package/scripts/lib/fixtures/figma-checks/button-missing-default.json +2 -1
- package/scripts/lib/fixtures/figma-checks/button-mui-ring.json +2 -1
- package/scripts/lib/fixtures/figma-checks/button-no-focus-variant.json +2 -1
- package/scripts/lib/fixtures/figma-checks/button-plain-frames.json +2 -1
- package/scripts/lib/fixtures/figma-checks/button-ring-child-not-absolute.json +2 -1
- package/scripts/lib/fixtures/figma-checks/button-ring-hidden.json +2 -1
- package/scripts/lib/fixtures/figma-checks/button-ring-unbound-colour.json +4 -3
- package/scripts/lib/fixtures/figma-checks/button-shadcn-filled.json +2 -1
- package/scripts/lib/fixtures/figma-checks/button-sparse.json +2 -1
- package/scripts/lib/fixtures/figma-checks/button-spread-zero.json +2 -1
- package/scripts/lib/fixtures/figma-checks/button-transparent-ring-child.json +2 -1
- package/scripts/lib/fixtures/figma-checks/button-vanilla-inside.json +2 -1
- package/scripts/lib/fixtures/figma-checks/button-vanilla-outside.json +2 -1
- package/scripts/lib/fixtures/figma-checks/button-wrong-combination.json +2 -1
- package/scripts/lib/fixtures/figma-checks/checkbox-checked-axis.real.json +2 -1
- package/scripts/lib/fixtures/figma-checks/checkbox-checked-synonym.json +2 -1
- package/scripts/lib/fixtures/figma-checks/checkbox-missing-selected.json +2 -1
- package/scripts/lib/fixtures/figma-checks/indicator-failed.json +106 -0
- package/scripts/lib/fixtures/figma-checks/input-control-layer-missing.json +2 -1
- package/scripts/lib/fixtures/figma-checks/input-control-layer-ring-on-wrapper.json +2 -1
- package/scripts/lib/fixtures/figma-checks/input-control-layer.json +2 -1
- package/scripts/lib/fixtures/figma-checks/input-mui-weight-unbound.json +2 -1
- package/scripts/lib/fixtures/figma-checks/input-mui.json +2 -1
- package/scripts/lib/fixtures/figma-checks/ring-single-mode.json +112 -0
- package/scripts/lib/fixtures/figma-checks/ring-translucent.json +111 -0
- package/scripts/lib/fixtures/figma-checks/sample-button.real.json +2 -1
- package/scripts/lib/fixtures/figma-checks/sample-ring-on-muted-raw.json +113 -0
- package/scripts/lib/fixtures/figma-checks/sample-ring-passes.json +169 -0
- package/scripts/lib/fixtures/figma-checks/surface-missing.json +108 -0
- package/scripts/lib/fixtures/figma-checks/surface-single-mode.json +112 -0
- package/scripts/lib/fixtures/figma-checks/surface-translucent.json +112 -0
- package/scripts/lib/fixtures/figma-checks/zygarden-ring-light-fails.json +113 -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.25.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. |
|
|
@@ -107,6 +107,8 @@ Then start with:
|
|
|
107
107
|
|
|
108
108
|
This is the reliable entry point — it runs environment setup first, ahead of anything else. (You can also just say *"let's set up my design system"*, but if you have other plugins installed that grab "let's build…" style phrases, the slash command guarantees ThroughLine takes the wheel.)
|
|
109
109
|
|
|
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
|
+
|
|
110
112
|
Update anytime with `/plugin marketplace update throughline-marketplace`.
|
|
111
113
|
|
|
112
114
|
#### Cursor, Codex, or a generic AGENTS.md agent
|
|
@@ -114,9 +116,9 @@ Update anytime with `/plugin marketplace update throughline-marketplace`.
|
|
|
114
116
|
Run the installer in your project — it stamps in the skills, the reference docs, the scripts, and the Figma MCP config for your tool:
|
|
115
117
|
|
|
116
118
|
```
|
|
117
|
-
npx @radicool/throughline@0.
|
|
118
|
-
npx @radicool/throughline@0.
|
|
119
|
-
npx @radicool/throughline@0.
|
|
119
|
+
npx @radicool/throughline@0.25.0 init --target=cursor # → .cursor/rules + .cursor/mcp.json
|
|
120
|
+
npx @radicool/throughline@0.25.0 init --target=codex # → prompts/ + AGENTS.md index + codex-mcp.toml
|
|
121
|
+
npx @radicool/throughline@0.25.0 init --target=generic # → skills/ + AGENTS.md index
|
|
120
122
|
```
|
|
121
123
|
|
|
122
124
|
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.
|
|
@@ -212,7 +214,7 @@ Future improvements and planned capabilities. Have a request? **[Open an issue](
|
|
|
212
214
|
- **Deeper Code Connect coverage** — richer Figma-to-code mappings as more plans support it.
|
|
213
215
|
- **Expanded component starters** — a larger foundational kit out of the box.
|
|
214
216
|
- **Richer status & auditing** — more from `/design-system-status`, including drift detection between Figma and code.
|
|
215
|
-
- **Built-in accessibility checks** — the color half is shipped. Eight semantic text-on-surface pairs are checked against WCAG AA's 4.5:1 when tokens are created in Figma, and derived again from the token source when they sync to code — in every mode, so a system that clears in light and fails in dark fails. A failing pair stops the build rather than warning. Components are checked too: on web frameworks, a Figma build stops when a focus state has no visible ring, and in JSX code the adherence gate is built to fail an icon-only button with no accessible name and a status badge that relies on color alone — proven by unit tests. The one real app it has run on had almost nothing for it to check, so it hasn't caught a bug in the wild yet.
|
|
217
|
+
- **Built-in accessibility checks** — the color half is shipped. Eight semantic text-on-surface pairs are checked against WCAG AA's 4.5:1 when tokens are created in Figma, and derived again from the token source when they sync to code — in every mode, so a system that clears in light and fails in dark fails. A failing pair stops the build rather than warning. Components are checked too: on web frameworks, a Figma build stops when a focus state has no visible ring, and in JSX code the adherence gate is built to fail an icon-only button with no accessible name and a status badge that relies on color alone — proven by unit tests. A Figma build also stops when a focus ring falls below WCAG's 3:1 against a surface the architect names for it, in any mode. The one real app it has run on had almost nothing for it to check, so it hasn't caught a bug in the wild yet.
|
|
216
218
|
- **Token fan-out to more platforms** — the DTCG token source is platform-neutral, and web targets are in daily use. Every target is **validated per build, not assumed**: `tokens:validate-output` checks generated output against its source, native Swift and Kotlin as well as web CSS, because the stock transforms have been measured emitting wrong-but-compiling values. iOS/Swift is a curated adapter whose Style Dictionary configuration ships as tested code, and Android/Kotlin uses the same configuration through the Tier 2 protocol. JavaScript theme output (MUI, a Tailwind v3 config) isn't checked yet.
|
|
217
219
|
- **Native component code generation** — producing a SwiftUI view or a Compose composable the way Storybook components are produced for React. This does not exist yet; it is a separate, larger effort than token fan-out, and the two were previously described as one roadmap item.
|
|
218
220
|
|
package/adapters/codex/AGENTS.md
CHANGED
|
@@ -19,6 +19,7 @@ ThroughLine builds a design system end to end. Load the matching prompt for the
|
|
|
19
19
|
|
|
20
20
|
## ThroughLine commands
|
|
21
21
|
|
|
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`.
|
|
22
23
|
- `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`.
|
|
23
24
|
- `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`.
|
|
24
25
|
- `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`.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
Check the Figma file against the design system without changing it. Use the
|
|
2
|
+
settings already in `design-system.json` (`figma.fileKey`, `project.uiFramework`,
|
|
3
|
+
`components.built`) rather than re-asking them. Scale explanation to
|
|
4
|
+
`user.codingLevel`.
|
|
5
|
+
|
|
6
|
+
1. **Know the file.** Read `figma.fileKey` from `design-system.json`. If it's
|
|
7
|
+
absent, stop and ask which file to check.
|
|
8
|
+
2. **Confirm the active file.** Run the preflight in
|
|
9
|
+
`.throughline/references/figma-scripting.md` ("confirm the *active*
|
|
10
|
+
file is your target") against that fileKey, and pin it with `figma_navigate`
|
|
11
|
+
(`lock: true`) for the run. Unpin when done.
|
|
12
|
+
3. **Screens.** Unless the user named them, ask which page holds the screens, and
|
|
13
|
+
optionally which screens on it. Run the snippet in
|
|
14
|
+
`.throughline/references/figma-adherence.md` verbatim, with
|
|
15
|
+
`const TARGET = { page, screens, fileKey }` (the fileKey from step 1, for the
|
|
16
|
+
links) and `const SKIP = []` filled. The script is the rule; don't re-derive its
|
|
17
|
+
checks.
|
|
18
|
+
4. **Existing component sets.** Ask which page holds the component sets, so only
|
|
19
|
+
that page is loaded. Ask which colour variables are the page surfaces the
|
|
20
|
+
components sit on, offering the file's likeliest default page surface (read the
|
|
21
|
+
names with `figma_get_variables`), or let the user skip focus contrast. For each
|
|
22
|
+
name in `components.built`, run
|
|
23
|
+
`.throughline/references/figma-checks.md` with `MODE = 'existing'` and
|
|
24
|
+
`EXPECT = { name, page, uiFramework, surfaces }` (`uiFramework` from
|
|
25
|
+
`project.uiFramework`). A name with no set on that page is reported as missing,
|
|
26
|
+
not as a failure of the others. When `focus-indicator` fails on a wrapped control
|
|
27
|
+
(an Input with a label, a Checkbox whose box is an inner frame), look at one focus
|
|
28
|
+
variant's layers before reporting it: if the ring is on an inner layer, run that
|
|
29
|
+
set again with `controlLayer` naming that layer, and say in the report that you
|
|
30
|
+
did.
|
|
31
|
+
5. **Report.** The screen gate gives one pass or fail for the page: list its
|
|
32
|
+
failures grouped by screen (the path's second segment), each with its detail and
|
|
33
|
+
link, then the advisories, the counts and any skipped rules. Then pass or fail
|
|
34
|
+
per component set, with whether focus contrast ran and against which surfaces. Say plainly what the
|
|
35
|
+
gate can't see: a frame drawn from scratch to look like a component, variables
|
|
36
|
+
that live only in a published library, and focus states drawn as an INSIDE
|
|
37
|
+
stroke.
|
|
38
|
+
|
|
39
|
+
Never edit the file to make a check pass, and never edit a token. A failure is
|
|
40
|
+
a finding for the user; fixing it is a separate, deliberate step.
|
|
41
|
+
|
|
@@ -177,8 +177,12 @@ deterministic naming):
|
|
|
177
177
|
way the executor does: `'spec'` mode before the first write and `'built'` mode
|
|
178
178
|
in the self-verify loop, with `EXPECT` built from your own matrix. You are the
|
|
179
179
|
architect here, so you name `controlLayer` yourself for a wrapped control (an
|
|
180
|
-
Input with a label or helper text)
|
|
181
|
-
|
|
180
|
+
Input with a label or helper text), and `surfaces` yourself: the colour-variable
|
|
181
|
+
names of the page surfaces the component sits on. A `fail` on the
|
|
182
|
+
`focus-indicator` check stops the build, as it would for the executor. A `fail`
|
|
183
|
+
on `focus-contrast` stops it too, naming its detail. A ring below 3:1 is fixed by
|
|
184
|
+
a token value, so don't change a variable or swap the ring to another one to make
|
|
185
|
+
it pass; a surface the file doesn't have is a wrong name in `surfaces`.
|
|
182
186
|
|
|
183
187
|
Checkpoint after each component: show all variants, confirm before the next.
|
|
184
188
|
|
|
@@ -366,8 +370,8 @@ any component built with the toggle + manual-swap fallback is listed in
|
|
|
366
370
|
component-builder --subject <Name> --entry <tmp>.json`. Build `<tmp>.json` with
|
|
367
371
|
`at` (an ISO timestamp you supply), `changed` (what was built), the attested checks `structural-read-back`,
|
|
368
372
|
`state-baseline` and `figma-name` from what the `figma-executor` returned (or
|
|
369
|
-
what your inline read-back found), `focus-indicator`
|
|
370
|
-
passed (not when it was skipped),
|
|
373
|
+
what your inline read-back found), `focus-indicator` and `focus-contrast`
|
|
374
|
+
each when that check ran and passed (not when it was skipped),
|
|
371
375
|
`review` when a reviewer ran, `screenshot` when one was captured, and
|
|
372
376
|
`advancedBecause`. The entry shape is
|
|
373
377
|
`.throughline/references/proof-bundle.md` — don't restate it here. Write
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
Check the Figma file against the design system without changing it. Use the
|
|
2
|
+
settings already in `design-system.json` (`figma.fileKey`, `project.uiFramework`,
|
|
3
|
+
`components.built`) rather than re-asking them. Scale explanation to
|
|
4
|
+
`user.codingLevel`.
|
|
5
|
+
|
|
6
|
+
1. **Know the file.** Read `figma.fileKey` from `design-system.json`. If it's
|
|
7
|
+
absent, stop and ask which file to check.
|
|
8
|
+
2. **Confirm the active file.** Run the preflight in
|
|
9
|
+
`.throughline/references/figma-scripting.md` ("confirm the *active*
|
|
10
|
+
file is your target") against that fileKey, and pin it with `figma_navigate`
|
|
11
|
+
(`lock: true`) for the run. Unpin when done.
|
|
12
|
+
3. **Screens.** Unless the user named them, ask which page holds the screens, and
|
|
13
|
+
optionally which screens on it. Run the snippet in
|
|
14
|
+
`.throughline/references/figma-adherence.md` verbatim, with
|
|
15
|
+
`const TARGET = { page, screens, fileKey }` (the fileKey from step 1, for the
|
|
16
|
+
links) and `const SKIP = []` filled. The script is the rule; don't re-derive its
|
|
17
|
+
checks.
|
|
18
|
+
4. **Existing component sets.** Ask which page holds the component sets, so only
|
|
19
|
+
that page is loaded. Ask which colour variables are the page surfaces the
|
|
20
|
+
components sit on, offering the file's likeliest default page surface (read the
|
|
21
|
+
names with `figma_get_variables`), or let the user skip focus contrast. For each
|
|
22
|
+
name in `components.built`, run
|
|
23
|
+
`.throughline/references/figma-checks.md` with `MODE = 'existing'` and
|
|
24
|
+
`EXPECT = { name, page, uiFramework, surfaces }` (`uiFramework` from
|
|
25
|
+
`project.uiFramework`). A name with no set on that page is reported as missing,
|
|
26
|
+
not as a failure of the others. When `focus-indicator` fails on a wrapped control
|
|
27
|
+
(an Input with a label, a Checkbox whose box is an inner frame), look at one focus
|
|
28
|
+
variant's layers before reporting it: if the ring is on an inner layer, run that
|
|
29
|
+
set again with `controlLayer` naming that layer, and say in the report that you
|
|
30
|
+
did.
|
|
31
|
+
5. **Report.** The screen gate gives one pass or fail for the page: list its
|
|
32
|
+
failures grouped by screen (the path's second segment), each with its detail and
|
|
33
|
+
link, then the advisories, the counts and any skipped rules. Then pass or fail
|
|
34
|
+
per component set, with whether focus contrast ran and against which surfaces. Say plainly what the
|
|
35
|
+
gate can't see: a frame drawn from scratch to look like a component, variables
|
|
36
|
+
that live only in a published library, and focus states drawn as an INSIDE
|
|
37
|
+
stroke.
|
|
38
|
+
|
|
39
|
+
Never edit the file to make a check pass, and never edit a token. A failure is
|
|
40
|
+
a finding for the user; fixing it is a separate, deliberate step.
|
|
41
|
+
|
|
@@ -181,8 +181,12 @@ deterministic naming):
|
|
|
181
181
|
way the executor does: `'spec'` mode before the first write and `'built'` mode
|
|
182
182
|
in the self-verify loop, with `EXPECT` built from your own matrix. You are the
|
|
183
183
|
architect here, so you name `controlLayer` yourself for a wrapped control (an
|
|
184
|
-
Input with a label or helper text)
|
|
185
|
-
|
|
184
|
+
Input with a label or helper text), and `surfaces` yourself: the colour-variable
|
|
185
|
+
names of the page surfaces the component sits on. A `fail` on the
|
|
186
|
+
`focus-indicator` check stops the build, as it would for the executor. A `fail`
|
|
187
|
+
on `focus-contrast` stops it too, naming its detail. A ring below 3:1 is fixed by
|
|
188
|
+
a token value, so don't change a variable or swap the ring to another one to make
|
|
189
|
+
it pass; a surface the file doesn't have is a wrong name in `surfaces`.
|
|
186
190
|
|
|
187
191
|
Checkpoint after each component: show all variants, confirm before the next.
|
|
188
192
|
|
|
@@ -370,8 +374,8 @@ any component built with the toggle + manual-swap fallback is listed in
|
|
|
370
374
|
component-builder --subject <Name> --entry <tmp>.json`. Build `<tmp>.json` with
|
|
371
375
|
`at` (an ISO timestamp you supply), `changed` (what was built), the attested checks `structural-read-back`,
|
|
372
376
|
`state-baseline` and `figma-name` from what the `figma-executor` returned (or
|
|
373
|
-
what your inline read-back found), `focus-indicator`
|
|
374
|
-
passed (not when it was skipped),
|
|
377
|
+
what your inline read-back found), `focus-indicator` and `focus-contrast`
|
|
378
|
+
each when that check ran and passed (not when it was skipped),
|
|
375
379
|
`review` when a reviewer ran, `screenshot` when one was captured, and
|
|
376
380
|
`advancedBecause`. The entry shape is
|
|
377
381
|
`.throughline/references/proof-bundle.md` — don't restate it here. Write
|
|
@@ -19,6 +19,7 @@ ThroughLine builds a design system end to end. Read the matching skill file for
|
|
|
19
19
|
|
|
20
20
|
## ThroughLine commands
|
|
21
21
|
|
|
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`.
|
|
22
23
|
- `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`.
|
|
23
24
|
- `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`.
|
|
24
25
|
- `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,41 @@
|
|
|
1
|
+
Check the Figma file against the design system without changing it. Use the
|
|
2
|
+
settings already in `design-system.json` (`figma.fileKey`, `project.uiFramework`,
|
|
3
|
+
`components.built`) rather than re-asking them. Scale explanation to
|
|
4
|
+
`user.codingLevel`.
|
|
5
|
+
|
|
6
|
+
1. **Know the file.** Read `figma.fileKey` from `design-system.json`. If it's
|
|
7
|
+
absent, stop and ask which file to check.
|
|
8
|
+
2. **Confirm the active file.** Run the preflight in
|
|
9
|
+
`.throughline/references/figma-scripting.md` ("confirm the *active*
|
|
10
|
+
file is your target") against that fileKey, and pin it with `figma_navigate`
|
|
11
|
+
(`lock: true`) for the run. Unpin when done.
|
|
12
|
+
3. **Screens.** Unless the user named them, ask which page holds the screens, and
|
|
13
|
+
optionally which screens on it. Run the snippet in
|
|
14
|
+
`.throughline/references/figma-adherence.md` verbatim, with
|
|
15
|
+
`const TARGET = { page, screens, fileKey }` (the fileKey from step 1, for the
|
|
16
|
+
links) and `const SKIP = []` filled. The script is the rule; don't re-derive its
|
|
17
|
+
checks.
|
|
18
|
+
4. **Existing component sets.** Ask which page holds the component sets, so only
|
|
19
|
+
that page is loaded. Ask which colour variables are the page surfaces the
|
|
20
|
+
components sit on, offering the file's likeliest default page surface (read the
|
|
21
|
+
names with `figma_get_variables`), or let the user skip focus contrast. For each
|
|
22
|
+
name in `components.built`, run
|
|
23
|
+
`.throughline/references/figma-checks.md` with `MODE = 'existing'` and
|
|
24
|
+
`EXPECT = { name, page, uiFramework, surfaces }` (`uiFramework` from
|
|
25
|
+
`project.uiFramework`). A name with no set on that page is reported as missing,
|
|
26
|
+
not as a failure of the others. When `focus-indicator` fails on a wrapped control
|
|
27
|
+
(an Input with a label, a Checkbox whose box is an inner frame), look at one focus
|
|
28
|
+
variant's layers before reporting it: if the ring is on an inner layer, run that
|
|
29
|
+
set again with `controlLayer` naming that layer, and say in the report that you
|
|
30
|
+
did.
|
|
31
|
+
5. **Report.** The screen gate gives one pass or fail for the page: list its
|
|
32
|
+
failures grouped by screen (the path's second segment), each with its detail and
|
|
33
|
+
link, then the advisories, the counts and any skipped rules. Then pass or fail
|
|
34
|
+
per component set, with whether focus contrast ran and against which surfaces. Say plainly what the
|
|
35
|
+
gate can't see: a frame drawn from scratch to look like a component, variables
|
|
36
|
+
that live only in a published library, and focus states drawn as an INSIDE
|
|
37
|
+
stroke.
|
|
38
|
+
|
|
39
|
+
Never edit the file to make a check pass, and never edit a token. A failure is
|
|
40
|
+
a finding for the user; fixing it is a separate, deliberate step.
|
|
41
|
+
|
|
@@ -177,8 +177,12 @@ deterministic naming):
|
|
|
177
177
|
way the executor does: `'spec'` mode before the first write and `'built'` mode
|
|
178
178
|
in the self-verify loop, with `EXPECT` built from your own matrix. You are the
|
|
179
179
|
architect here, so you name `controlLayer` yourself for a wrapped control (an
|
|
180
|
-
Input with a label or helper text)
|
|
181
|
-
|
|
180
|
+
Input with a label or helper text), and `surfaces` yourself: the colour-variable
|
|
181
|
+
names of the page surfaces the component sits on. A `fail` on the
|
|
182
|
+
`focus-indicator` check stops the build, as it would for the executor. A `fail`
|
|
183
|
+
on `focus-contrast` stops it too, naming its detail. A ring below 3:1 is fixed by
|
|
184
|
+
a token value, so don't change a variable or swap the ring to another one to make
|
|
185
|
+
it pass; a surface the file doesn't have is a wrong name in `surfaces`.
|
|
182
186
|
|
|
183
187
|
Checkpoint after each component: show all variants, confirm before the next.
|
|
184
188
|
|
|
@@ -366,8 +370,8 @@ any component built with the toggle + manual-swap fallback is listed in
|
|
|
366
370
|
component-builder --subject <Name> --entry <tmp>.json`. Build `<tmp>.json` with
|
|
367
371
|
`at` (an ISO timestamp you supply), `changed` (what was built), the attested checks `structural-read-back`,
|
|
368
372
|
`state-baseline` and `figma-name` from what the `figma-executor` returned (or
|
|
369
|
-
what your inline read-back found), `focus-indicator`
|
|
370
|
-
passed (not when it was skipped),
|
|
373
|
+
what your inline read-back found), `focus-indicator` and `focus-contrast`
|
|
374
|
+
each when that check ran and passed (not when it was skipped),
|
|
371
375
|
`review` when a reviewer ran, `screenshot` when one was captured, and
|
|
372
376
|
`advancedBecause`. The entry shape is
|
|
373
377
|
`.throughline/references/proof-bundle.md` — don't restate it here. Write
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@radicool/throughline",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.25.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": {
|