@radicool/throughline 0.12.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/LICENSE +21 -0
- package/README.md +214 -0
- package/adapters/codex/AGENTS.md +29 -0
- package/adapters/codex/codex-mcp.toml +4 -0
- package/adapters/codex/prompts/component-builder.md +272 -0
- package/adapters/codex/prompts/component-pipeline.md +81 -0
- package/adapters/codex/prompts/design-system-audit.md +122 -0
- package/adapters/codex/prompts/design-system-status.md +41 -0
- package/adapters/codex/prompts/figma-environment-setup.md +456 -0
- package/adapters/codex/prompts/icon-system-builder.md +268 -0
- package/adapters/codex/prompts/new-component.md +13 -0
- package/adapters/codex/prompts/repository-builder.md +163 -0
- package/adapters/codex/prompts/retrofit-planner.md +136 -0
- package/adapters/codex/prompts/start.md +22 -0
- package/adapters/codex/prompts/storybook-chromatic-builder.md +261 -0
- package/adapters/codex/prompts/sync-figma-tokens.md +22 -0
- package/adapters/codex/prompts/token-builder.md +361 -0
- package/adapters/codex/prompts/token-crosswalk-builder.md +120 -0
- package/adapters/codex/prompts/token-sheet-builder.md +162 -0
- package/adapters/codex/prompts/token-sync-layer.md +232 -0
- package/adapters/cursor/.cursor/commands/design-system-status.md +41 -0
- package/adapters/cursor/.cursor/commands/new-component.md +13 -0
- package/adapters/cursor/.cursor/commands/start.md +22 -0
- package/adapters/cursor/.cursor/commands/sync-figma-tokens.md +22 -0
- package/adapters/cursor/.cursor/mcp.json +14 -0
- package/adapters/cursor/.cursor/rules/component-builder.mdc +276 -0
- package/adapters/cursor/.cursor/rules/component-pipeline.mdc +85 -0
- package/adapters/cursor/.cursor/rules/design-system-audit.mdc +126 -0
- package/adapters/cursor/.cursor/rules/figma-environment-setup.mdc +460 -0
- package/adapters/cursor/.cursor/rules/icon-system-builder.mdc +272 -0
- package/adapters/cursor/.cursor/rules/repository-builder.mdc +167 -0
- package/adapters/cursor/.cursor/rules/retrofit-planner.mdc +140 -0
- package/adapters/cursor/.cursor/rules/storybook-chromatic-builder.mdc +265 -0
- package/adapters/cursor/.cursor/rules/token-builder.mdc +365 -0
- package/adapters/cursor/.cursor/rules/token-crosswalk-builder.mdc +124 -0
- package/adapters/cursor/.cursor/rules/token-sheet-builder.mdc +166 -0
- package/adapters/cursor/.cursor/rules/token-sync-layer.mdc +236 -0
- package/adapters/generic/AGENTS.md +46 -0
- package/adapters/generic/commands/design-system-status.md +41 -0
- package/adapters/generic/commands/new-component.md +13 -0
- package/adapters/generic/commands/start.md +22 -0
- package/adapters/generic/commands/sync-figma-tokens.md +22 -0
- package/adapters/generic/skills/component-builder/SKILL.md +272 -0
- package/adapters/generic/skills/component-pipeline/SKILL.md +81 -0
- package/adapters/generic/skills/design-system-audit/SKILL.md +122 -0
- package/adapters/generic/skills/figma-environment-setup/SKILL.md +456 -0
- package/adapters/generic/skills/icon-system-builder/SKILL.md +268 -0
- package/adapters/generic/skills/repository-builder/SKILL.md +163 -0
- package/adapters/generic/skills/retrofit-planner/SKILL.md +136 -0
- package/adapters/generic/skills/storybook-chromatic-builder/SKILL.md +261 -0
- package/adapters/generic/skills/token-builder/SKILL.md +361 -0
- package/adapters/generic/skills/token-crosswalk-builder/SKILL.md +120 -0
- package/adapters/generic/skills/token-sheet-builder/SKILL.md +162 -0
- package/adapters/generic/skills/token-sync-layer/SKILL.md +232 -0
- package/package.json +29 -0
- package/references/brainstorm-before-build.md +139 -0
- package/references/brownfield-retrofit.md +93 -0
- package/references/coding-level.md +70 -0
- package/references/crosswalk-schema.md +113 -0
- package/references/figma-component-standards.md +532 -0
- package/references/figma-publishing.md +125 -0
- package/references/figma-scripting.md +278 -0
- package/references/manifest-schema.md +341 -0
- package/references/scaling-up-handoff.md +61 -0
- package/references/sync-adapters.md +141 -0
- package/scripts/README.md +78 -0
- package/scripts/adapters/emit-codex.mjs +58 -0
- package/scripts/adapters/emit-cursor.mjs +26 -0
- package/scripts/adapters/emit-generic.mjs +41 -0
- package/scripts/adapters/generate.mjs +73 -0
- package/scripts/adapters/read-sources.mjs +54 -0
- package/scripts/adapters/translate.mjs +51 -0
- package/scripts/build-reverse-index.mjs +56 -0
- package/scripts/crosswalk.schema.json +33 -0
- package/scripts/grep-color-usage.mjs +143 -0
- package/scripts/guard-token-removal.mjs +95 -0
- package/scripts/install.mjs +143 -0
- package/scripts/lib/crosswalk.mjs +91 -0
- package/scripts/validate-crosswalk.mjs +96 -0
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
# Icon system builder
|
|
2
|
+
|
|
3
|
+
End state: a Figma page named **Icons** containing the relevant icon set as
|
|
4
|
+
**scalable, well-named components**, ready to be consumed by components (skill 4)
|
|
5
|
+
and swapped via instance properties.
|
|
6
|
+
|
|
7
|
+
## Core principle: don't make the agent draw 1,700 icons
|
|
8
|
+
|
|
9
|
+
The expensive, wrong path is the agent generating icon components one by one, by
|
|
10
|
+
hand, via the write mechanism — slow and token-hungry. Get to the end state via
|
|
11
|
+
the **cheapest mechanism that is also fully automated and produces clean,
|
|
12
|
+
well-named components.** "Cheapest" is not just the agent tokens: a mechanism that
|
|
13
|
+
burns near-zero tokens but makes the *user* hunt down a community file, duplicate
|
|
14
|
+
it, and copy components by hand isn't actually cheap — it just moves the cost onto
|
|
15
|
+
them. **The library determines the mechanism, deterministically** — same library,
|
|
16
|
+
same path every run.
|
|
17
|
+
|
|
18
|
+
### Lucide → fetch the official SVGs directly (default)
|
|
19
|
+
|
|
20
|
+
**Default for Lucide: fetch the curated subset straight from the official source
|
|
21
|
+
repo and batch-componentize it.** Lucide publishes every icon as a uniform 24px
|
|
22
|
+
SVG at a deterministic path (`github.com/lucide-icons/lucide`, `icons/<name>.svg`),
|
|
23
|
+
and the filename *is* the canonical name (`arrow-right` ↔ `ArrowRight` in
|
|
24
|
+
`lucide-react`). So the agent can do the whole thing hands-off:
|
|
25
|
+
|
|
26
|
+
1. Resolve the subset to kebab-case icon names (see name validation below) and
|
|
27
|
+
pin a release **tag** — ideally the tag matching the installed `lucide-react`
|
|
28
|
+
version, so the Figma mirror and the code package are the same generation.
|
|
29
|
+
2. Batch-fetch each
|
|
30
|
+
`https://raw.githubusercontent.com/lucide-icons/lucide/<tag>/icons/<name>.svg`.
|
|
31
|
+
A **404 means that icon doesn't exist at that version** — report it and let the
|
|
32
|
+
user pick a replacement. (This *is* the name-validation gate, for free.)
|
|
33
|
+
3. In one scripted pass, turn each SVG into a component via
|
|
34
|
+
`figma.createNodeFromSvg(svg)`, convert to a component, name it per the naming
|
|
35
|
+
contract (Step 3), and set the base size.
|
|
36
|
+
|
|
37
|
+
This is **fully automated, official source-of-truth, deterministic-named, and
|
|
38
|
+
needs no manual user steps** — strictly better than a community-file copy for a
|
|
39
|
+
library shaped like this. This is **not** the old "fetch SVGs off a website and
|
|
40
|
+
hand-prep them" anti-pattern: that meant a human manually downloading and cleaning
|
|
41
|
+
files. Batch-grabbing the official repo by deterministic path and scripting
|
|
42
|
+
`createNodeFromSvg` is cheap *and* hands-off.
|
|
43
|
+
|
|
44
|
+
**Fallbacks (only if the fetch path is blocked or the user prefers):** a vetted
|
|
45
|
+
Lucide community component file, or the official Lucide importer plugin — e.g. if
|
|
46
|
+
GitHub is unreachable, the user is on a restricted network, or they explicitly
|
|
47
|
+
want the community file. Name the specific resource and surface its license first
|
|
48
|
+
(see below).
|
|
49
|
+
|
|
50
|
+
### Tabler & Phosphor → fetch the official SVGs directly (same as Lucide)
|
|
51
|
+
|
|
52
|
+
**Tabler and Phosphor are first-class libraries built by the exact Lucide
|
|
53
|
+
mechanism** — uniform per-icon SVGs published at a deterministic repo path where the
|
|
54
|
+
filename *is* the canonical name, so they get the same fully-automated,
|
|
55
|
+
official-source-of-truth, hands-off treatment (batch-fetch → `createNodeFromSvg` →
|
|
56
|
+
`createComponentFromNode`), not a community-file copy. This path is **proven**: a
|
|
57
|
+
greenfield run imported the Tabler subset by deterministic path with zero 404s and
|
|
58
|
+
bound the vector strokes to `text/primary` for theming. Prefer it whenever the user's
|
|
59
|
+
brand specifies Tabler or Phosphor (both are common picks).
|
|
60
|
+
|
|
61
|
+
- **Tabler** (MIT, 24px stroke): `github.com/tabler/tabler-icons`, per-icon at
|
|
62
|
+
`icons/outline/<name>.svg` (and `icons/filled/<name>.svg` for the filled set). Pin a
|
|
63
|
+
release tag matching the installed `@tabler/icons-react` generation. A 404 is the
|
|
64
|
+
name-validation gate, same as Lucide.
|
|
65
|
+
- **Phosphor** (MIT, 256px): `github.com/phosphor-icons/core`, per-icon at
|
|
66
|
+
`assets/<weight>/<name>.svg` where weight ∈ `thin|light|regular|bold|fill|duotone`
|
|
67
|
+
(regular has no suffix; others are `<name>-<weight>.svg`). Pick one weight as the
|
|
68
|
+
base to match the code package, pin the tag, and fetch that weight's files.
|
|
69
|
+
|
|
70
|
+
After fetch, **bind the vector strokes/fills to `text/primary`** (or the icon color
|
|
71
|
+
token) so the icons theme with the system, and name per the Step 3 contract. Fallbacks
|
|
72
|
+
(only if the fetch is blocked) mirror Lucide's: the library's official Figma community
|
|
73
|
+
file or importer plugin, license surfaced first.
|
|
74
|
+
|
|
75
|
+
### Material → official community file / importer (default)
|
|
76
|
+
|
|
77
|
+
Material has **variant axes** (outlined / rounded / sharp × fill / weight / grade /
|
|
78
|
+
optical size), so there is no single clean per-icon file to grab — a direct repo
|
|
79
|
+
fetch isn't the clean default it is for Lucide. **Default to the official Material
|
|
80
|
+
Symbols community file or the official Material importer plugin** (Apache-2.0):
|
|
81
|
+
name the specific vetted resource, say why, surface the license, and get the
|
|
82
|
+
user's confirmation (see below). Only consider a direct fetch if the user pins one
|
|
83
|
+
specific style, and even then prefer the importer. Never hand-draw or generate
|
|
84
|
+
one-by-one.
|
|
85
|
+
|
|
86
|
+
### Custom → batched SVG import
|
|
87
|
+
|
|
88
|
+
The user's own SVGs, brought in via **batched import + componentize** (never
|
|
89
|
+
hand-drawn, never one at a time). The sync layer later turns these into code via
|
|
90
|
+
its SVGR pipeline — see Step 3.5.
|
|
91
|
+
|
|
92
|
+
**Choosing a *different* mechanism on different runs for the *same* library is a
|
|
93
|
+
bug:** the library fixes the choice, so it must be deterministic.
|
|
94
|
+
|
|
95
|
+
## Default to a CURATED SUBSET, not the whole library
|
|
96
|
+
|
|
97
|
+
Most projects need 40–120 icons, not 1,700+. Importing the entire library bloats
|
|
98
|
+
the file and hurts performance (one of the goals is a performant setup). So:
|
|
99
|
+
|
|
100
|
+
Run `.throughline/references/brainstorm-before-build.md` to establish **which icons the user
|
|
101
|
+
actually needs** — start from a sensible UI-essentials set (arrows, close, check,
|
|
102
|
+
search, menu, chevrons, common actions) and let them add domain-specific ones.
|
|
103
|
+
Only import the full library if the user explicitly wants it. Recorded subset can
|
|
104
|
+
grow later by re-running.
|
|
105
|
+
|
|
106
|
+
**Validate every subset name against the library version before building.** Icon
|
|
107
|
+
libraries add and **remove** icons between versions — e.g. `lucide-react` 1.x
|
|
108
|
+
dropped the brand icons (`figma`, `instagram`, `linkedin`, `twitter`, `youtube`,
|
|
109
|
+
…), so a subset listing them would build Figma components named after icons that
|
|
110
|
+
**don't exist in code**, silently breaking the Figma↔code name contract (the whole
|
|
111
|
+
point of deterministic naming below). Before importing: resolve each requested name
|
|
112
|
+
against the **actual library at the version in play** — if `lucide-react`/the
|
|
113
|
+
library package is already installed, check its real export list (and pin
|
|
114
|
+
`icons.version` to that); otherwise check the version's published icon manifest.
|
|
115
|
+
**Report any names that don't resolve and let the user pick replacements** — never
|
|
116
|
+
assume a name exists or invent a near-match. Brand/logo icons especially: confirm
|
|
117
|
+
they're in the chosen version or source them as custom SVGs (mechanism #3).
|
|
118
|
+
|
|
119
|
+
## Name the resource and license (community-file / importer paths)
|
|
120
|
+
|
|
121
|
+
When a path uses an **unofficial** community file or importer plugin — Material's
|
|
122
|
+
default, or a Lucide *fallback* — those resources are variable in quality (some
|
|
123
|
+
popular plugins are reported buggy/slow). So: name the *specific* vetted resource
|
|
124
|
+
you intend to use, briefly say why, surface its license for commercial use, and
|
|
125
|
+
let the user confirm or pick another before proceeding. Don't silently grab
|
|
126
|
+
whatever's first. Verify the link is still live — don't assume a stale URL/file
|
|
127
|
+
key works; if the named resource has moved, search Figma Community for the
|
|
128
|
+
official/most-installed equivalent and confirm before using.
|
|
129
|
+
|
|
130
|
+
Default candidates for these paths, so the choice is consistent across runs:
|
|
131
|
+
|
|
132
|
+
- **Lucide fallback** → Lucide's **official Figma resource** (the Lucide-team
|
|
133
|
+
community file, or the official "Lucide Icons" importer plugin). MIT-licensed.
|
|
134
|
+
Only used if the official-SVG fetch (the Lucide default, above) is blocked.
|
|
135
|
+
- **Material** → the **official Material Symbols** community file, or the official
|
|
136
|
+
Material importer plugin. Apache-2.0.
|
|
137
|
+
- **Custom** → the user's own SVGs via batched import.
|
|
138
|
+
|
|
139
|
+
The **Lucide official-SVG fetch is the default and needs no resource-vetting
|
|
140
|
+
step** — the source is the library's own repo, not a third-party file — but still
|
|
141
|
+
pin the version tag and report any names that 404. If you genuinely cannot reach
|
|
142
|
+
the Lucide repo *and* cannot confirm a community file or importer, **say so and
|
|
143
|
+
ask the user** which resource to use — never invent a source.
|
|
144
|
+
|
|
145
|
+
## Step 1 — Choose library + mechanism
|
|
146
|
+
|
|
147
|
+
- Ask which library: **Lucide** (the shadcn default; outline only), **Tabler**,
|
|
148
|
+
**Phosphor**, **Material**, or **custom** (user brings SVGs). Record in
|
|
149
|
+
`icons.library`.
|
|
150
|
+
- Determine the subset (brainstorm, above).
|
|
151
|
+
- The library fixes the mechanism (Core principle): **Lucide / Tabler / Phosphor →
|
|
152
|
+
fetch official SVGs from the repo by deterministic path; Material → official
|
|
153
|
+
community file / importer; custom → batched SVG import.** Pin the version tag for
|
|
154
|
+
the fetch libraries. Only name + confirm a specific community-file/importer resource
|
|
155
|
+
for the paths that use one (Material, or a fetch-library fallback).
|
|
156
|
+
|
|
157
|
+
## Step 2 — Bring icons in
|
|
158
|
+
|
|
159
|
+
Execute the library's mechanism:
|
|
160
|
+
|
|
161
|
+
- **Lucide (default):** batch-fetch the subset's SVGs from
|
|
162
|
+
`raw.githubusercontent.com/lucide-icons/lucide/<tag>/icons/<name>.svg`, then in
|
|
163
|
+
one scripted pass build each into a named component via
|
|
164
|
+
`figma.createNodeFromSvg`. Report any 404s and let the user pick replacements
|
|
165
|
+
before finishing. No manual user steps. (If the fetch is blocked, fall back to
|
|
166
|
+
the community file / importer and guide the copy.)
|
|
167
|
+
- **Material / community-file path:** guide the user through copying the file (or
|
|
168
|
+
the relevant components) into their **Icons** page, or walk the importer
|
|
169
|
+
install/run and subset selection.
|
|
170
|
+
- **Custom SVGs:** batch-import and componentize them.
|
|
171
|
+
|
|
172
|
+
This is a Figma-authoring step — sequential, with the user in the loop; no
|
|
173
|
+
subagents. When scripting the SVG-to-component pass, follow
|
|
174
|
+
`.throughline/references/figma-scripting.md`.
|
|
175
|
+
|
|
176
|
+
## Step 3 — Normalize: page, naming, sizing, variants
|
|
177
|
+
|
|
178
|
+
Whatever mechanism brought them in, ensure the end state is consistent:
|
|
179
|
+
|
|
180
|
+
- All icons live on a page named **Icons**.
|
|
181
|
+
- Each icon is a **component** (not a raw frame), scalable without quality loss.
|
|
182
|
+
- **Naming is a contract, not cosmetics.** The Figma names must map
|
|
183
|
+
*deterministically* to the code package's export names (`icon/arrow-right` ↔
|
|
184
|
+
`ArrowRight` in `lucide-react`). This naming is what lets components bind an
|
|
185
|
+
icon slot in Figma to the right code import later — get it wrong and
|
|
186
|
+
components silently show different icons in Figma vs code. Follow the library's
|
|
187
|
+
canonical naming so the mapping is automatic.
|
|
188
|
+
- **Sizing/variant** convention as needed — a base size (e.g. 24px) and any
|
|
189
|
+
size variants the system wants; stroke consistent with the library.
|
|
190
|
+
- Icons should be ready to drop into components and swapped via instance/variant
|
|
191
|
+
properties.
|
|
192
|
+
- **Lay the page out cleanly.** Arrange the icons in an orderly grid inside an
|
|
193
|
+
**auto-layout Frame placed directly on the Icons page** (never a Section —
|
|
194
|
+
Sections have no auto layout, and these skills do **not** wrap the Frame in one;
|
|
195
|
+
ignore the Figma Console MCP server's "create a Section first" instruction),
|
|
196
|
+
never floating on bare canvas, and present the whole set on a
|
|
197
|
+
**single documentation card** with a header — name, short description, status,
|
|
198
|
+
last updated — *one card for all icons*, not one per icon. When you script this
|
|
199
|
+
grid via `figma_execute`, follow
|
|
200
|
+
`.throughline/references/figma-scripting.md` — for a large icon set,
|
|
201
|
+
build manual rows rather than one `layoutWrap = "WRAP"` frame (it times out), and
|
|
202
|
+
watch the `resize()` axis-lock trap. Follow
|
|
203
|
+
`.throughline/references/figma-component-standards.md` (auto layout,
|
|
204
|
+
no overlapping text or frames) and run its visual-validation loop **and its
|
|
205
|
+
"Post-build audit (REQUIRED before handoff)" read-back checklist** (container
|
|
206
|
+
is a Frame on the page with no Section anywhere above it, auto layout present, fills/text/radius/spacing bound
|
|
207
|
+
to variables, deterministic names) before handing off.
|
|
208
|
+
|
|
209
|
+
## Step 3.5 — Code side: install the package (icons are already code)
|
|
210
|
+
|
|
211
|
+
Library icons (Lucide/Material) have their real source of truth in an **npm
|
|
212
|
+
package** — `lucide-react`, `@mui/icons-material` — not in Figma. Figma is a
|
|
213
|
+
*visual mirror* of that package. So the code side is reached by **installing the
|
|
214
|
+
package, never by generating hundreds of icon components from Figma.**
|
|
215
|
+
|
|
216
|
+
If a repo exists (`workspace.stage` is `local-git` or `github`), offer to install
|
|
217
|
+
the matching package and record `icons.packageInstalled` = `true` and
|
|
218
|
+
`icons.version` (so the sync layer can later check the Figma mirror and the
|
|
219
|
+
installed package are the same generation). If there's no repo yet, skip this and
|
|
220
|
+
note it'll happen when they set one up — the Figma page is fully usable now.
|
|
221
|
+
|
|
222
|
+
**Custom icons are the exception** — there's no package, so they reach code as
|
|
223
|
+
generated components via the sync layer's SVGR pipeline (not here). This skill
|
|
224
|
+
just gets custom SVGs into Figma as components; the sync layer turns them into
|
|
225
|
+
code.
|
|
226
|
+
|
|
227
|
+
## Step 3.6 — Publish checkpoint (unlocks typed icon dropdowns later)
|
|
228
|
+
|
|
229
|
+
Icons are the main thing components swap into slots. For a component to expose a
|
|
230
|
+
typed icon **dropdown** (`INSTANCE_SWAP`), the icons must be published to a team
|
|
231
|
+
library first — Figma rejects unpublished local component keys for swap targets.
|
|
232
|
+
This is the natural moment to publish, *before* components are built.
|
|
233
|
+
|
|
234
|
+
Read `.throughline/references/figma-publishing.md` and follow it:
|
|
235
|
+
|
|
236
|
+
- If `figma.canPublish` is unknown, ask once whether they're on a paid Figma plan
|
|
237
|
+
(Professional or higher); record it.
|
|
238
|
+
- **Paid plan:** offer to walk them through **Assets → Libraries → Publish** (the
|
|
239
|
+
plugin cannot publish for them — instruct, then verify). On confirmation, set
|
|
240
|
+
`figma.libraryPublished` = `true` and `figma.publishedAt`. Mention that adding
|
|
241
|
+
components later means a quick re-publish.
|
|
242
|
+
- **Free plan, or they decline:** completely fine — components will use the
|
|
243
|
+
toggle + manual-swap fallback and can be upgraded to typed dropdowns later if
|
|
244
|
+
they ever publish. Don't block or frame it as a failure.
|
|
245
|
+
|
|
246
|
+
Keep it optional and non-blocking; the Icons page is fully usable either way.
|
|
247
|
+
|
|
248
|
+
## Step 4 — Checkpoint and hand off
|
|
249
|
+
|
|
250
|
+
Show the user the Icons page. Iterate if needed. Update the manifest:
|
|
251
|
+
`icons.built` = `true`, `icons.library`, `icons.version` (for library icons),
|
|
252
|
+
`icons.subset` (the imported set), and `icons.packageInstalled` if the code
|
|
253
|
+
package was installed. Append `icon-system-builder` to `completedSkills`. Note
|
|
254
|
+
they can re-run to add more icons. Offer next steps (components consume these
|
|
255
|
+
icons; the sync layer handles custom-icon code and version-drift checks).
|
|
256
|
+
|
|
257
|
+
## What this skill must NOT do
|
|
258
|
+
|
|
259
|
+
- Never **hand-draw** icons or generate them one-by-one. (Scripting
|
|
260
|
+
`createNodeFromSvg` over a batch of official Lucide SVGs is fine and is the
|
|
261
|
+
default — that's automated import, not hand-drawing.)
|
|
262
|
+
- Never import 1,700 icons by default — curate to what's needed.
|
|
263
|
+
- Never make the user manually copy a community file when the library has a clean
|
|
264
|
+
official per-icon SVG repo the agent can fetch hands-off (Lucide).
|
|
265
|
+
- Never grab an unnamed/unvetted community file or importer silently — name it,
|
|
266
|
+
surface the license, let the user verify. (The Lucide official-repo fetch is
|
|
267
|
+
exempt — it's the library's own source.)
|
|
268
|
+
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# Repository builder
|
|
2
|
+
|
|
3
|
+
Turns the user's working folder into a scalable monorepo and advances their
|
|
4
|
+
version-control stage. Defaults: **pnpm + Turborepo**, with a layout ready to
|
|
5
|
+
grow into a full app:
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
my-design-system/
|
|
9
|
+
├── design-system.json (the manifest, already here)
|
|
10
|
+
├── package.json (workspace root)
|
|
11
|
+
├── pnpm-workspace.yaml
|
|
12
|
+
├── turbo.json
|
|
13
|
+
├── .gitignore
|
|
14
|
+
├── .env.example
|
|
15
|
+
├── packages/
|
|
16
|
+
│ ├── tokens/ (synced token output lands here — skill 6)
|
|
17
|
+
│ └── ui/ (components / Storybook live here — skill 7)
|
|
18
|
+
└── apps/ (empty, ready for a Next.js app later)
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Calibrate first
|
|
22
|
+
|
|
23
|
+
Read `user.codingLevel` from the manifest and `.throughline/references/coding-level.md`.
|
|
24
|
+
Everything below describes the *actions*, which are identical for every user.
|
|
25
|
+
**How much you explain** each concept scales with the level — `new` gets plain-
|
|
26
|
+
language teaching of repos, env files, and secrets; `comfortable` gets terse
|
|
27
|
+
action statements. The hard secret-safety rules never scale.
|
|
28
|
+
|
|
29
|
+
## The folder → local-git → github progression
|
|
30
|
+
|
|
31
|
+
**Scope check first.** If the user is bringing an **existing app** to retrofit or
|
|
32
|
+
migrate (not scaffolding a clean monorepo) — or the repo work is entangled with a
|
|
33
|
+
larger re-architecture — that has outgrown this skill. Follow
|
|
34
|
+
`.throughline/references/scaling-up-handoff.md`: surface risks and major parts, confirm scope,
|
|
35
|
+
and brainstorm/plan first (handing off to Superpowers if available, else planning
|
|
36
|
+
natively — never required). For a normal scaffold-from-scratch, continue here.
|
|
37
|
+
|
|
38
|
+
The user is at one of three `workspace.stage` values. This skill advances them
|
|
39
|
+
one step at a time, introducing each concept only when its payoff is concrete.
|
|
40
|
+
Read the current stage from the manifest and pick up where they are.
|
|
41
|
+
|
|
42
|
+
### Stage A → scaffold the monorepo (still just a folder)
|
|
43
|
+
|
|
44
|
+
Create the workspace files (root `package.json`, `pnpm-workspace.yaml`,
|
|
45
|
+
`turbo.json`, `packages/tokens`, `packages/ui`, `apps/`, a sensible
|
|
46
|
+
`.gitignore`, and a `.env.example`). Record `repo.packageManager` = `pnpm`,
|
|
47
|
+
`repo.monorepo` = `turborepo`.
|
|
48
|
+
|
|
49
|
+
For `new` users, explain in one line what this is: "A monorepo is just one folder
|
|
50
|
+
that holds several related projects together — here, your tokens and your
|
|
51
|
+
components, with room to add an app later." For `comfortable` users, just state
|
|
52
|
+
what you scaffolded.
|
|
53
|
+
|
|
54
|
+
Checkpoint: show the structure, let the user look before committing anything.
|
|
55
|
+
|
|
56
|
+
### Stage B → add local version history (`git init`)
|
|
57
|
+
|
|
58
|
+
This is the soft-nudge seam from the design: the moment code exists, version
|
|
59
|
+
history earns its keep. If `workspace.stage` is still `folder`, offer it:
|
|
60
|
+
|
|
61
|
+
- `new`: "Right now your folder has no 'history' — if something breaks there's no
|
|
62
|
+
undo. Git gives your folder a memory: every change is saved as a checkpoint you
|
|
63
|
+
can see and roll back. Want me to turn that on? It's one step and stays entirely
|
|
64
|
+
on your computer — nothing goes online yet."
|
|
65
|
+
- `comfortable`: "Want me to `git init` and make the first commit?"
|
|
66
|
+
|
|
67
|
+
If yes: `git init`, ensure `.gitignore` covers `node_modules`, `.env`, build
|
|
68
|
+
output; make an initial commit. Set `workspace.stage` and `repo.stage` to
|
|
69
|
+
`local-git`. Confirm the user can see they now have version history.
|
|
70
|
+
|
|
71
|
+
**Do not force git.** A user can stay in `folder` if they insist, but most will
|
|
72
|
+
want it once there's code. The token-sync skill needs at least `local-git`, so
|
|
73
|
+
it will re-offer this if skipped.
|
|
74
|
+
|
|
75
|
+
### Stage C → connect to GitHub (remote, PRs, CI)
|
|
76
|
+
|
|
77
|
+
Only when the user wants what GitHub provides — backup, PRs for token-sync
|
|
78
|
+
review, CI for Storybook/Chromatic. Frame it as "push what you already have
|
|
79
|
+
somewhere safe and shareable," not "make an empty repo and figure out what goes
|
|
80
|
+
in it" — they already have a working local repo.
|
|
81
|
+
|
|
82
|
+
**Detect `gh` (the GitHub CLI):**
|
|
83
|
+
|
|
84
|
+
- If `gh` is present and authenticated: offer to run `gh repo create` — but
|
|
85
|
+
**show the exact command and what it will do first**, and get approval before
|
|
86
|
+
running. A `new` user may not know what that command does to their account, so
|
|
87
|
+
explain: "This creates a repository on your GitHub account and connects your
|
|
88
|
+
local folder to it." Never create the repo, set branch protection, or change
|
|
89
|
+
settings silently.
|
|
90
|
+
- If `gh` is absent: **first recommend installing it.** It's the single thing
|
|
91
|
+
that turns repo creation from a fiddly multi-step browser chore into one
|
|
92
|
+
automated command — exactly the friction this plugin exists to remove. Say so
|
|
93
|
+
plainly and offer to guide a quick one-time setup:
|
|
94
|
+
- **Install:** macOS `brew install gh`; Windows `winget install GitHub.CLI`;
|
|
95
|
+
Linux via the system package manager (or cli.github.com). Then authenticate
|
|
96
|
+
with `gh auth login` — walk `new` users through the browser prompts.
|
|
97
|
+
- Never install software silently — show the command, explain what it does, get
|
|
98
|
+
a yes first. Once installed and authenticated, proceed with the `gh` path
|
|
99
|
+
above (show the `gh repo create` command, get approval, then run it).
|
|
100
|
+
- **If they decline or can't install:** fall back to the manual browser path
|
|
101
|
+
with the exact click path. For `new` users be maximally explicit: go to
|
|
102
|
+
github.com, click New repository, name it, leave it empty (don't initialize
|
|
103
|
+
with a README), Create, then copy the commands GitHub shows for "push an
|
|
104
|
+
existing repository" and run them. Verify the push succeeded.
|
|
105
|
+
|
|
106
|
+
On success, set `workspace.stage` and `repo.stage` to `github` and record
|
|
107
|
+
`repo.remote`. Append `repository-builder` to `completedSkills`.
|
|
108
|
+
|
|
109
|
+
## Secrets: the part most people have never done
|
|
110
|
+
|
|
111
|
+
This is where users with low coding experience get stuck — many have never made
|
|
112
|
+
an env file or added a secret to a "vault." Handle it with care, scaled to
|
|
113
|
+
`codingLevel`, but with the hard rules constant. There are **two distinct
|
|
114
|
+
homes** for a secret, and conflating them is a common mistake — make the
|
|
115
|
+
distinction explicit for `new`/`some` users:
|
|
116
|
+
|
|
117
|
+
1. **Local development → a `.env` file.** A plain text file in the repo root
|
|
118
|
+
holding `KEY=value` lines, used when running things on your own computer.
|
|
119
|
+
**It must be gitignored** so it never gets committed. The repo ships a
|
|
120
|
+
`.env.example` (no real values, just the key names) as a template — explain
|
|
121
|
+
that `new` users copy it to `.env` and fill in real values.
|
|
122
|
+
2. **Production / CI → the host's secrets store.** GitHub Actions has its own
|
|
123
|
+
encrypted **secrets vault** (Settings → Secrets and variables → Actions). CI
|
|
124
|
+
can't read your local `.env`, so any secret CI needs (e.g.
|
|
125
|
+
`CHROMATIC_PROJECT_TOKEN`) must be added there separately.
|
|
126
|
+
|
|
127
|
+
The hard rules, regardless of level:
|
|
128
|
+
- The secret **value never passes through this chat.** Don't ask the user to
|
|
129
|
+
paste it to you. Tell them the key name and exactly where the value goes; they
|
|
130
|
+
place it themselves.
|
|
131
|
+
- Secrets **never get committed.** `.env` is gitignored; only `.env.example`
|
|
132
|
+
(key names, no values) is committed.
|
|
133
|
+
- the agent **never** types a secret into a web form or creates a GitHub secret on
|
|
134
|
+
the user's behalf — it gives the click path and the key name.
|
|
135
|
+
|
|
136
|
+
For `new` users, teach the *why* once ("a secret key is like a password for a
|
|
137
|
+
service; if it's committed to code, anyone who sees your repo can use it — that's
|
|
138
|
+
why it lives in a gitignored file locally and an encrypted vault in
|
|
139
|
+
production"). Then give the literal steps. **Verify**: after they add a secret,
|
|
140
|
+
have them confirm it's set (e.g. re-run the workflow and check CI goes green),
|
|
141
|
+
because a beginner who pastes it wrong has no other signal.
|
|
142
|
+
|
|
143
|
+
This skill itself usually only sets up `.env.example` and the `.gitignore`. The
|
|
144
|
+
actual secret *values* (Chromatic, etc.) get added when the skill that needs
|
|
145
|
+
them runs (Storybook/Chromatic in skill 7) — but explain the env-file concept
|
|
146
|
+
here so it's familiar by then.
|
|
147
|
+
|
|
148
|
+
## Hand off
|
|
149
|
+
|
|
150
|
+
Tell the user what's unlocked at their new stage. If they came here heading
|
|
151
|
+
toward token sync, point them to it ("now we can turn your Figma tokens into real
|
|
152
|
+
code files in `packages/tokens`"). Don't auto-run the next skill.
|
|
153
|
+
|
|
154
|
+
## What this skill must NOT do
|
|
155
|
+
|
|
156
|
+
- Never commit a `.env` or any secret value.
|
|
157
|
+
- Never create a GitHub repo, branch protection, or secret silently — always
|
|
158
|
+
show the command/path and get approval.
|
|
159
|
+
- Never enter a secret into a web form or accept a secret value in chat.
|
|
160
|
+
- Never force git on a user who declines (but explain what they're deferring).
|
|
161
|
+
- Never give a beginner a lesser setup — only less explanation is fine, never
|
|
162
|
+
fewer capabilities.
|
|
163
|
+
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# Retrofit planner (orchestrator)
|
|
2
|
+
|
|
3
|
+
Sequences a brownfield retrofit through the safe 7-phase order, gating each phase on a
|
|
4
|
+
human confirmation. Like `component-pipeline`, this skill holds **zero domain logic of
|
|
5
|
+
its own** — it is a sequencer that invokes the real skills and the phase work, and only
|
|
6
|
+
updates the manifest fields it owns (`retrofit.*`, `completedSkills`). All the
|
|
7
|
+
actual work lives in the skills it calls, so this orchestrator doesn't rot when they
|
|
8
|
+
improve.
|
|
9
|
+
|
|
10
|
+
**Before anything, read `.throughline/references/brownfield-retrofit.md`** —
|
|
11
|
+
the read discipline, the 7 guardrails, the safe sequence, and the verification triad
|
|
12
|
+
are the rules this skill enforces as gates.
|
|
13
|
+
|
|
14
|
+
## When to use vs. the individual skills
|
|
15
|
+
|
|
16
|
+
Use this for a **complete retrofit**, especially across multiple sessions. For a single
|
|
17
|
+
isolated step (just the audit, just the crosswalk), run that skill directly. This is the
|
|
18
|
+
"converge my mature system onto tokens, end to end, without breaking the live app" flow.
|
|
19
|
+
|
|
20
|
+
## Calibrate
|
|
21
|
+
|
|
22
|
+
Read `user.codingLevel` (`.throughline/references/coding-level.md`). A retrofit
|
|
23
|
+
touches Figma, tokens, code, CI, and a live app — for `new` users explain each phase and
|
|
24
|
+
why its ordering matters the first time; for `comfortable` users be terse. The phases and
|
|
25
|
+
gates are identical across levels.
|
|
26
|
+
|
|
27
|
+
## Prerequisites
|
|
28
|
+
|
|
29
|
+
Read the manifest. This orchestrator assumes a brownfield situation
|
|
30
|
+
(`tokens.intakeMode: "retrofit"`, or `workspace.origin` is an existing repo/monorepo). If
|
|
31
|
+
the audit hasn't run yet (`audit.ranAt` is `null`), start at the audit phase below. If
|
|
32
|
+
none of the brownfield markers are set, this is probably greenfield — point the user to
|
|
33
|
+
the normal build skills instead.
|
|
34
|
+
|
|
35
|
+
## Decision-journal offer (default-on)
|
|
36
|
+
|
|
37
|
+
At the start of a retrofit, offer to scaffold a decision journal at `docs/design-system/`
|
|
38
|
+
with `specs/ plans/ spikes/ findings/ decisions/ handoffs/`. **Recommend yes** —
|
|
39
|
+
retrofits are multi-session and the journal is the human decision trail (complementary to
|
|
40
|
+
the manifest's machine state) — but allow the user to decline. Record the choice in
|
|
41
|
+
`retrofit.journalScaffolded`. This is the only artifact this skill creates directly.
|
|
42
|
+
|
|
43
|
+
## Detect the stack, don't assume it (§11)
|
|
44
|
+
|
|
45
|
+
Before running phases that shell out (sync, baseline, code, cleanup), detect what the
|
|
46
|
+
repo actually uses — read its `package.json` scripts for the real type-check, build,
|
|
47
|
+
visual-test, and token commands. The case study used Chromatic + `build-storybook` +
|
|
48
|
+
`tokens:sync`/`tokens:validate`; a real repo may differ. Map each phase onto the repo's
|
|
49
|
+
actual commands, or degrade gracefully and say what's missing — never assert a command
|
|
50
|
+
that doesn't exist.
|
|
51
|
+
|
|
52
|
+
## The safe sequence (confirm between EVERY phase)
|
|
53
|
+
|
|
54
|
+
Set `retrofit.phase` to the current phase as you enter it, so a later session can resume
|
|
55
|
+
exactly here. Confirm the goal first, then walk the phases. **Each gate is a hard stop:
|
|
56
|
+
do not advance without explicit confirmation** — the gates are what keep the live app
|
|
57
|
+
intact and make the retrofit resumable.
|
|
58
|
+
|
|
59
|
+
### Phase 1 — `audit` (invoke `design-system-audit`)
|
|
60
|
+
|
|
61
|
+
Invoke `design-system-audit`: size the code surface, inventory the Figma file with
|
|
62
|
+
verified per-class reads, compute `percentSemantic`. **Gate:** show the audit results and
|
|
63
|
+
the right-sizing read ("~90% semantic → renames + cleanup, not a rewrite"). Confirm before
|
|
64
|
+
continuing. Capture the rollback baseline (Figma version checkpoint / token export) now if
|
|
65
|
+
`figma-environment-setup` didn't already. On first entry, set `retrofit.startedAt` to the
|
|
66
|
+
current ISO timestamp if it is unset.
|
|
67
|
+
|
|
68
|
+
### Phase 2 — `refine` (invoke `token-builder` brownfield branch)
|
|
69
|
+
|
|
70
|
+
Invoke `token-builder`'s refine-in-place branch: rename/realign variables **in place**,
|
|
71
|
+
preserving IDs, with a binding-survival audit before and after each rename (guardrail 3).
|
|
72
|
+
**Gate:** show the before/after binding counts are equal (no bindings severed) and the
|
|
73
|
+
refined variable names. Confirm before continuing. **Never delete-and-recreate.**
|
|
74
|
+
|
|
75
|
+
### Phase 3 — `rebind`
|
|
76
|
+
|
|
77
|
+
Reconcile components onto the refined variables, preserving their Figma IDs. There is no
|
|
78
|
+
dedicated skill for this — drive it directly here: verify components still reference the
|
|
79
|
+
(renamed, same-id) variables, and fix any that drifted. **Gate:** confirm components still
|
|
80
|
+
render bound. This is also the natural point to build the crosswalk if not yet done —
|
|
81
|
+
offer `token-crosswalk-builder` (it reads the `audit` section to seed rows and wires
|
|
82
|
+
`tokens:validate`).
|
|
83
|
+
|
|
84
|
+
### Phase 4 — `sync` (invoke `token-sync-layer` brownfield branch)
|
|
85
|
+
|
|
86
|
+
Invoke `token-sync-layer` with the brownfield transforms (channel alpha, opacity
|
|
87
|
+
0–100→0–1, float32 rounding at the export boundary, `/opacity`→`color-mix`). It lands a
|
|
88
|
+
reviewable PR per its own rules. **Gate:** confirm the sync PR before continuing.
|
|
89
|
+
|
|
90
|
+
### Phase 5 — `baseline` (invoke `storybook-chromatic-builder`)
|
|
91
|
+
|
|
92
|
+
Capture a Chromatic baseline **before** any code retrofit, so intended drift-fixes are
|
|
93
|
+
distinguishable from regressions. **Gate:** confirm the baseline is green and captured.
|
|
94
|
+
This ordering is not optional — baseline *after* the code change throws away the signal.
|
|
95
|
+
|
|
96
|
+
### Phase 6 — `code` (dual output)
|
|
97
|
+
|
|
98
|
+
Retrofit the codebase with **dual output**: new and old tokens coexist during the
|
|
99
|
+
transition, so nothing breaks mid-migration. Use the crosswalk reverse index
|
|
100
|
+
(`tokens:reverse-index`) to semi-automate the SCSS/Tailwind swaps. Run the verification
|
|
101
|
+
triad as you go — `check-types`, `build-storybook` + Chromatic, **and run the actual app**
|
|
102
|
+
+ spot-check 5–7 routes (the build alone is blind to story-unreachable SCSS). **Gate:**
|
|
103
|
+
confirm the triad passes before continuing.
|
|
104
|
+
|
|
105
|
+
### Phase 7 — `cleanup`
|
|
106
|
+
|
|
107
|
+
Remove the old token outputs **only after** the repo-wide token-removal guard returns
|
|
108
|
+
**zero references** (`guard-token-removal.mjs`) — deleted Tailwind utilities are silent
|
|
109
|
+
no-ops that `tsc`/build won't catch (guardrail 4). **Gate:** show the guard reporting zero
|
|
110
|
+
references, then confirm removal. Re-run the verification triad after removal.
|
|
111
|
+
|
|
112
|
+
When cleanup is verified, set `retrofit.phase: "done"` and `retrofit.completedAt`, and
|
|
113
|
+
append `retrofit-planner` to `completedSkills`.
|
|
114
|
+
|
|
115
|
+
## Resumability
|
|
116
|
+
|
|
117
|
+
Because each phase is gated and `retrofit.phase` is written on entry, a stop at any point
|
|
118
|
+
leaves a clean resume point. `figma-environment-setup` reads `retrofit.phase` on the next
|
|
119
|
+
`/start` and routes back here at the right phase. Never silently restart from the top —
|
|
120
|
+
resume where the manifest says.
|
|
121
|
+
|
|
122
|
+
## What this skill must NOT do
|
|
123
|
+
|
|
124
|
+
- Never reimplement what the sub-skills do — only sequence them and drive the
|
|
125
|
+
no-dedicated-skill phases (rebind, code, cleanup). If you're writing token/sync logic
|
|
126
|
+
here, stop and invoke the real skill.
|
|
127
|
+
- Never skip a confirmation between phases — the gates keep the live app intact and make
|
|
128
|
+
the retrofit resumable.
|
|
129
|
+
- Never delete-and-recreate variables (guardrail 3), baseline after the code retrofit
|
|
130
|
+
(phase 5 before 6), or remove old outputs before the zero-reference grep passes
|
|
131
|
+
(guardrail 4).
|
|
132
|
+
- Never write another skill's manifest fields — own only `retrofit.*` and
|
|
133
|
+
`completedSkills`. The audit owns `audit.*`; the crosswalk owns `tokenCrosswalk`.
|
|
134
|
+
- Never assert the case-study toolchain — detect the repo's real commands or degrade
|
|
135
|
+
gracefully.
|
|
136
|
+
|