@motion-proto/live-tokens 0.73.0 → 0.75.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/.claude/skills/live-tokens-check-compliance/SKILL.md +33 -38
- package/.claude/skills/live-tokens-create-component/SKILL copy.md +196 -0
- package/.claude/skills/live-tokens-create-component/SKILL.md +198 -146
- package/.claude/skills/live-tokens-create-component/references/contract-tests.md +95 -52
- package/.claude/skills/live-tokens-create-component/references/intrinsics.md +2 -2
- package/.claude/skills/live-tokens-create-component/references/linked-siblings.md +2 -2
- package/.claude/skills/live-tokens-create-component/references/sketch-mode.md +12 -12
- package/.claude/skills/live-tokens-create-component/references/token-naming.md +2 -1
- package/.claude/skills/live-tokens-create-page/SKILL.md +187 -0
- package/.claude/skills/live-tokens-create-page/references/interaction-sources.md +66 -0
- package/.claude/skills/live-tokens-create-page/references/layout-sources.md +87 -0
- package/.claude/skills/live-tokens-create-theme/SKILL.md +84 -0
- package/.claude/skills/live-tokens-create-theme/references/design-directions.md +94 -0
- package/.claude/skills/live-tokens-fix-findings/SKILL.md +69 -60
- package/.claude/skills/live-tokens-pick-component/SKILL.md +64 -79
- package/.claude/skills/live-tokens-set-colors/SKILL.md +149 -0
- package/.claude/skills/live-tokens-set-colors/references/color-anchors.md +80 -0
- package/.claude/skills/live-tokens-set-geometry/SKILL.md +121 -0
- package/.claude/skills/live-tokens-set-geometry/references/geometry-anchors.md +63 -0
- package/.claude/skills/live-tokens-set-type/SKILL.md +93 -0
- package/.claude/skills/live-tokens-set-type/references/type-anchors.md +60 -0
- package/CHANGELOG.md +194 -0
- package/README.md +27 -18
- package/bin/check-component.mjs +91 -19
- package/bin/check-page.mjs +105 -24
- package/bin/cli.mjs +154 -97
- package/bin/contractRunner.mjs +945 -0
- package/bin/create.mjs +1 -1
- package/bin/lib/catalogue.mjs +37 -30
- package/bin/lib/findings.mjs +46 -15
- package/bin/lib/liveState.mjs +110 -0
- package/bin/lib/report.mjs +3 -3
- package/bin/lib/tokenVocabulary.mjs +4 -4
- package/bin/migrate-routes.mjs +5 -5
- package/bin/migrate.mjs +4 -4
- package/bin/save-theme.mjs +176 -0
- package/bin/set-colors.mjs +189 -0
- package/bin/{adjust.mjs → set-geometry.mjs} +25 -57
- package/bin/{set-fonts.mjs → set-type.mjs} +26 -62
- package/dist-plugin/{chunk-W6Y4BWFB.js → chunk-6WGFOJXO.js} +22 -0
- package/dist-plugin/{chunk-RIXO2E55.js → chunk-PDNL4NC5.js} +9 -2
- package/dist-plugin/{chunk-YLCOIGQC.js → chunk-SWXRVZKT.js} +98 -2
- package/dist-plugin/{dataPaths-BhWzd5cL.d.ts → dataPaths-BpIK_Obx.d.cts} +1 -0
- package/dist-plugin/{dataPaths-BhWzd5cL.d.cts → dataPaths-BpIK_Obx.d.ts} +1 -0
- package/dist-plugin/index.cjs +366 -148
- package/dist-plugin/index.d.cts +1 -1
- package/dist-plugin/index.d.ts +1 -1
- package/dist-plugin/index.js +226 -130
- package/dist-plugin/migrateData/index.cjs +121 -2
- package/dist-plugin/migrateData/index.d.cts +1 -1
- package/dist-plugin/migrateData/index.d.ts +1 -1
- package/dist-plugin/migrateData/index.js +3 -3
- package/dist-plugin/{generateColorsAndType → setColors}/index.cjs +594 -499
- package/dist-plugin/{generateColorsAndType → setColors}/index.d.cts +34 -25
- package/dist-plugin/{generateColorsAndType → setColors}/index.d.ts +34 -25
- package/dist-plugin/{generateColorsAndType → setColors}/index.js +48 -66
- package/dist-plugin/{adjust → setGeometry}/index.cjs +166 -48
- package/dist-plugin/{adjust → setGeometry}/index.d.cts +6 -6
- package/dist-plugin/{adjust → setGeometry}/index.d.ts +6 -6
- package/dist-plugin/{adjust → setGeometry}/index.js +51 -45
- package/dist-plugin/{fontPairing → setType}/index.cjs +19 -4
- package/dist-plugin/{fontPairing → setType}/index.d.cts +2 -2
- package/dist-plugin/{fontPairing → setType}/index.d.ts +2 -2
- package/dist-plugin/{fontPairing → setType}/index.js +1 -1
- package/dist-plugin/{themeTypes-DSV3Zisf.d.cts → themeTypes-BxRtuN5V.d.cts} +1 -1
- package/dist-plugin/{themeTypes-DSV3Zisf.d.ts → themeTypes-BxRtuN5V.d.ts} +1 -1
- package/dist-plugin/tokensCssMigrations/index.d.cts +1 -1
- package/dist-plugin/tokensCssMigrations/index.d.ts +1 -1
- package/dist-plugin/tokensCssMigrations/index.js +1 -1
- package/package.json +36 -8
- package/src/app/site.css +19 -9
- package/src/editor/bootstrap.ts +2 -0
- package/src/editor/component-editor/CollapsibleSectionEditor.svelte +4 -4
- package/src/editor/component-editor/DialogEditor.svelte +4 -4
- package/src/editor/component-editor/MenuSelectEditor.svelte +4 -1
- package/src/editor/component-editor/SegmentedControlEditor.svelte +6 -1
- package/src/editor/component-editor/TabBarEditor.svelte +1 -1
- package/src/editor/component-editor/TableEditor.svelte +2 -2
- package/src/editor/component-editor/scaffolding/TokenLayout.svelte +6 -3
- package/src/editor/component-editor/scaffolding/VariantGroup.svelte +41 -20
- package/src/editor/core/components/adjustAliases.ts +59 -45
- package/src/editor/core/components/aliasKinds.ts +9 -5
- package/src/editor/core/preview/themePreview.ts +9 -2
- package/src/editor/core/sketch/sketchLayer.ts +22 -0
- package/src/editor/core/store/editorStore.ts +10 -1
- package/src/editor/core/themes/{generateColorsAndType.ts → buildColors.ts} +84 -98
- package/src/editor/core/themes/liveStateStream.ts +26 -0
- package/src/editor/core/themes/migrations/2026-09-03-drop-legacy-component-keys.ts +62 -0
- package/src/editor/core/themes/migrations/2026-09-07-stroke-role-renames.ts +52 -0
- package/src/editor/core/themes/migrations/index.ts +4 -0
- package/src/editor/core/themes/themeDocumentSync.ts +22 -11
- package/src/editor/core/themes/themeService.ts +9 -2
- package/src/editor/docs/content/themes-workflow.md +2 -2
- package/src/editor/docs/content.generated.ts +1 -1
- package/src/editor/overlay/LiveEditorOverlay.svelte +519 -28
- package/src/editor/pages/ComponentEditorPage.svelte +17 -1
- package/src/editor/pages/liveTokensEditorHandle.ts +23 -0
- package/src/editor/skill-atlas/SkillAtlas.svelte +76 -574
- package/src/editor/skill-atlas/TreeCanvas.svelte +263 -0
- package/src/editor/skill-atlas/TreeNodeCard.svelte +136 -53
- package/src/editor/skill-atlas/edges.ts +31 -0
- package/src/editor/skill-atlas/skillSources.generated.ts +29 -24
- package/src/editor/skill-atlas/skillTrees.ts +19 -3687
- package/src/editor/skill-atlas/trees/check-compliance.ts +183 -0
- package/src/editor/skill-atlas/trees/create-component.ts +275 -0
- package/src/editor/skill-atlas/trees/create-page.ts +320 -0
- package/src/editor/skill-atlas/trees/create-theme.ts +255 -0
- package/src/editor/skill-atlas/trees/fix-findings.ts +469 -0
- package/src/editor/skill-atlas/trees/pick-component.ts +300 -0
- package/src/editor/skill-atlas/trees/set-colors.ts +148 -0
- package/src/editor/skill-atlas/trees/set-geometry.ts +136 -0
- package/src/editor/skill-atlas/trees/set-type.ts +142 -0
- package/src/editor/skill-atlas/types.ts +3 -4
- package/src/editor/skill-atlas/wireLayout.ts +287 -0
- package/src/live-tokens/data/colors-and-type/autumn.json +1 -37
- package/src/live-tokens/data/colors-and-type/default.json +1 -37
- package/src/live-tokens/data/colors-and-type/halloween.json +1 -37
- package/src/live-tokens/data/colors-and-type/midnight-study.json +1 -37
- package/src/live-tokens/data/colors-and-type/ocean.json +1 -37
- package/src/live-tokens/data/colors-and-type/royal-velvet.json +1 -37
- package/src/live-tokens/data/colors-and-type/sketchy.json +1 -37
- package/src/live-tokens/data/colors-and-type/spring-meadow.json +1 -37
- package/src/live-tokens/data/colors-and-type/sunset.json +1 -37
- package/src/live-tokens/data/themes/autumn.json +16 -52
- package/src/live-tokens/data/themes/halloween.json +16 -52
- package/src/live-tokens/data/themes/midnight-study.json +16 -52
- package/src/live-tokens/data/themes/ocean.json +16 -52
- package/src/live-tokens/data/themes/royal-velvet.json +16 -52
- package/src/live-tokens/data/themes/sketchy.json +16 -52
- package/src/live-tokens/data/themes/spring-meadow.json +16 -52
- package/src/live-tokens/data/themes/sunset.json +16 -52
- package/src/live-tokens/data/tokens.generated.css +0 -36
- package/src/system/components/Badge.svelte +7 -0
- package/src/system/components/Button.svelte +7 -0
- package/src/system/components/Callout.svelte +10 -6
- package/src/system/components/Card.svelte +23 -4
- package/src/system/components/CodeSnippet.svelte +4 -3
- package/src/system/components/CollapsibleSection.svelte +23 -8
- package/src/system/components/CornerBadge.svelte +6 -0
- package/src/system/components/Dialog.svelte +13 -6
- package/src/system/components/IconButton.svelte +9 -0
- package/src/system/components/Image.svelte +8 -0
- package/src/system/components/ImageLightbox.svelte +6 -0
- package/src/system/components/InlineEditActions.svelte +7 -0
- package/src/system/components/Input.svelte +7 -0
- package/src/system/components/MenuSelect.svelte +7 -0
- package/src/system/components/Notification.svelte +7 -0
- package/src/system/components/Panel.svelte +6 -0
- package/src/system/components/ProgressBar.svelte +5 -0
- package/src/system/components/RadioButton.svelte +11 -5
- package/src/system/components/SectionDivider.svelte +8 -0
- package/src/system/components/SegmentedControl.svelte +6 -0
- package/src/system/components/SideNavigation.svelte +6 -0
- package/src/system/components/Slider.svelte +7 -4
- package/src/system/components/TabBar.svelte +15 -9
- package/src/system/components/Table.svelte +8 -3
- package/src/system/components/Toggle.svelte +4 -4
- package/src/system/components/Tooltip.svelte +6 -0
- package/src/testing-js/chunk-AO7EZHYV.js +776 -0
- package/src/testing-js/chunk-AO7EZHYV.js.map +1 -0
- package/src/testing-js/chunk-FAFOAWYL.js +39 -0
- package/src/testing-js/chunk-FAFOAWYL.js.map +1 -0
- package/src/testing-js/chunk-L73N4NSO.js +23 -0
- package/src/testing-js/chunk-L73N4NSO.js.map +1 -0
- package/src/testing-js/chunk-LXR3MN6N.js +3063 -0
- package/src/testing-js/chunk-LXR3MN6N.js.map +1 -0
- package/src/testing-js/chunk-ZMSX6CXR.js +53 -0
- package/src/testing-js/chunk-ZMSX6CXR.js.map +1 -0
- package/src/testing-js/component-alias.contract.js +81 -0
- package/src/testing-js/component-alias.contract.js.map +1 -0
- package/src/testing-js/component-editor.contract.js +62 -0
- package/src/testing-js/component-editor.contract.js.map +1 -0
- package/src/testing-js/component-render.contract.js +568 -0
- package/src/testing-js/component-render.contract.js.map +1 -0
- package/src/testing-js/index.d.ts +293 -0
- package/src/testing-js/index.js +222 -0
- package/src/testing-js/index.js.map +1 -0
- package/src/testing-js/registry.contract.js +39 -0
- package/src/testing-js/registry.contract.js.map +1 -0
- package/src/testing-js/vitest-BE6uGF31.d.ts +73 -0
- package/src/testing-js/vitest.d.ts +3 -0
- package/src/testing-js/vitest.js +13 -0
- package/src/testing-js/vitest.js.map +1 -0
- package/template/README.md +13 -0
- package/template/_gitignore +2 -0
- package/template/package.json +2 -1
- package/template/src/pages/Home.svelte +4 -18
- package/.claude/skills/live-tokens-adjust-geometry/SKILL.md +0 -93
- package/.claude/skills/live-tokens-build-page/SKILL.md +0 -103
- package/.claude/skills/live-tokens-build-page/references/layout-sources.md +0 -48
- package/.claude/skills/live-tokens-generate-theme/SKILL.md +0 -156
- package/.claude/skills/live-tokens-generate-theme/references/mood-vocabulary.md +0 -43
- package/.claude/skills/live-tokens-generate-theme/references/named-themes.md +0 -18
- package/.claude/skills/live-tokens-generate-theme/references/style-vocabulary.md +0 -35
- package/.claude/skills/live-tokens-pair-fonts/SKILL.md +0 -90
- package/bin/generate-theme.mjs +0 -260
package/bin/check-page.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Static validator for a live-tokens page.
|
|
2
2
|
//
|
|
3
3
|
// Asserts that a page satisfies the contract described in the
|
|
4
|
-
// live-tokens-
|
|
4
|
+
// live-tokens-create-page skill: it is assembled from catalogue components, and
|
|
5
5
|
// every value in its CSS is a theme token rather than a literal. The rules and
|
|
6
6
|
// their default severities are in PAGE_RULES; each is overridable per project
|
|
7
7
|
// (live-tokens.config.json) or per run (--off/--warn/--error/--strict), because
|
|
@@ -26,10 +26,13 @@ export const PAGE_RULES = {
|
|
|
26
26
|
'color-literal': 'error',
|
|
27
27
|
'reserved-route': 'error',
|
|
28
28
|
'site-css-in-main': 'error',
|
|
29
|
+
'raw-text-axis': 'error',
|
|
29
30
|
'dimension-literal': 'warn',
|
|
30
31
|
'hardcoded-columns': 'warn',
|
|
31
|
-
'raw-text-axis': 'warn',
|
|
32
32
|
'missing-source': 'warn',
|
|
33
|
+
'control-size': 'warn',
|
|
34
|
+
'multiple-primary': 'warn',
|
|
35
|
+
'danger-without-dialog': 'warn',
|
|
33
36
|
};
|
|
34
37
|
|
|
35
38
|
// Directories that hold the system, not pages built on it.
|
|
@@ -45,10 +48,17 @@ const DEEP_IMPORT_PATTERNS = [
|
|
|
45
48
|
|
|
46
49
|
const TEXT_AXES = ['font-size', 'font-family', 'font-weight', 'line-height', 'letter-spacing'];
|
|
47
50
|
|
|
51
|
+
// The single-axis scales in tokens.css. A text style bundle carries its axis
|
|
52
|
+
// as a suffix (--body-md-font-size, --code-font-family), so no bundle name
|
|
53
|
+
// matches, and neither does a custom property the page declares itself. A
|
|
54
|
+
// weight alone cannot move the scale or the fonts, so --font-weight-* is not one.
|
|
55
|
+
const SINGLE_AXIS_TOKEN =
|
|
56
|
+
/^--(?:font-size|line-height|letter-spacing)-|^--font-(?:sans|serif|mono|display|editorial)$/;
|
|
57
|
+
|
|
48
58
|
// The geometry the theme owns: spacing, stroke, radius, and shadow all have a
|
|
49
|
-
// token scale, and `
|
|
50
|
-
// minimum width, a max content width) is layout, has no scale, and
|
|
51
|
-
// literal.
|
|
59
|
+
// token scale, and `set-geometry` moves them. Sizing (a hero's height, a
|
|
60
|
+
// column's minimum width, a max content width) is layout, has no scale, and
|
|
61
|
+
// stays literal.
|
|
52
62
|
const THEMED_GEOMETRY = /^(padding|margin|gap|row-gap|column-gap|border|outline|inset|top|right|bottom|left|box-shadow|text-shadow)(-|$)|-radius$/;
|
|
53
63
|
|
|
54
64
|
// A local two-up or three-up is a layout. From four columns on, a hardcoded
|
|
@@ -184,7 +194,10 @@ function tagAttributes(code, start) {
|
|
|
184
194
|
return { attrs, end: tagEnd };
|
|
185
195
|
}
|
|
186
196
|
|
|
187
|
-
/**
|
|
197
|
+
/**
|
|
198
|
+
* Props a page passes that the component does not declare, values outside a
|
|
199
|
+
* prop's union, and a shipped component the page sizes itself.
|
|
200
|
+
*/
|
|
188
201
|
function checkComponentUsage(code, imports, add) {
|
|
189
202
|
for (const [local, entry] of imports) {
|
|
190
203
|
const props = entry.props;
|
|
@@ -203,11 +216,64 @@ function checkComponentUsage(code, imports, add) {
|
|
|
203
216
|
if (allowed && value !== null && !allowed.has(value)) {
|
|
204
217
|
add('unknown-prop-value', index, `${entry.name} ${name}="${value}" is not one of ${[...allowed].join(', ')}`);
|
|
205
218
|
}
|
|
219
|
+
if (name === 'size' && entry.origin === 'shipped') {
|
|
220
|
+
add(
|
|
221
|
+
'control-size',
|
|
222
|
+
index,
|
|
223
|
+
`${entry.name} ${value === null ? 'is sized here' : `size="${value}"`}. Drop it for the shipped default, or retune ${entry.name} for the whole project in /live-tokens/components.`,
|
|
224
|
+
);
|
|
225
|
+
}
|
|
206
226
|
}
|
|
207
227
|
}
|
|
208
228
|
}
|
|
209
229
|
}
|
|
210
230
|
|
|
231
|
+
/**
|
|
232
|
+
* One finding when a page holds more than one primary Button, at the second of
|
|
233
|
+
* them. Emphasis is what the variant carries, so a second primary leaves the
|
|
234
|
+
* page with no single most important action. A Button with no variant is
|
|
235
|
+
* primary, the component's default.
|
|
236
|
+
*/
|
|
237
|
+
function checkPrimaryActions(code, imports, add) {
|
|
238
|
+
const primaries = [];
|
|
239
|
+
for (const [local, entry] of imports) {
|
|
240
|
+
if (entry.id !== 'button') continue;
|
|
241
|
+
for (const m of code.matchAll(new RegExp(`<${local}(?=[\\s/>])`, 'g'))) {
|
|
242
|
+
const tag = tagAttributes(code, m.index);
|
|
243
|
+
const variant = tag?.attrs.find((a) => a.name === 'variant');
|
|
244
|
+
if (tag && (variant === undefined || variant.value === 'primary')) primaries.push(m.index);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
if (primaries.length < 2) return;
|
|
248
|
+
primaries.sort((a, b) => a - b);
|
|
249
|
+
add(
|
|
250
|
+
'multiple-primary',
|
|
251
|
+
primaries[1],
|
|
252
|
+
`${primaries.length} primary Buttons in this page. Keep the most important action primary and make the other ${primaries.length - 1} secondary.`,
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* One finding when a page holds a danger Button and imports no Dialog. A
|
|
258
|
+
* danger action destroys saved work, and the page has nothing to confirm it.
|
|
259
|
+
*/
|
|
260
|
+
function checkDestructiveActions(code, imports, add) {
|
|
261
|
+
if ([...imports.values()].some((entry) => entry.id === 'dialog')) return;
|
|
262
|
+
for (const [local, entry] of imports) {
|
|
263
|
+
if (entry.id !== 'button' && entry.id !== 'iconbutton') continue;
|
|
264
|
+
for (const m of code.matchAll(new RegExp(`<${local}(?=[\\s/>])`, 'g'))) {
|
|
265
|
+
const tag = tagAttributes(code, m.index);
|
|
266
|
+
if (!tag?.attrs.some((a) => a.name === 'variant' && a.value === 'danger')) continue;
|
|
267
|
+
add(
|
|
268
|
+
'danger-without-dialog',
|
|
269
|
+
m.index,
|
|
270
|
+
`${entry.name} variant="danger" with no Dialog in this page. A destructive action confirms in a Dialog before it runs.`,
|
|
271
|
+
);
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
211
277
|
/** The object literal enclosing `index`, found by balancing braces outward. */
|
|
212
278
|
function enclosingObject(text, index) {
|
|
213
279
|
let depth = 0;
|
|
@@ -267,6 +333,8 @@ function checkFile(file, text, vocab, root) {
|
|
|
267
333
|
if (local) imports.set(local, entry);
|
|
268
334
|
}
|
|
269
335
|
checkComponentUsage(code, imports, add);
|
|
336
|
+
checkPrimaryActions(code, imports, add);
|
|
337
|
+
checkDestructiveActions(code, imports, add);
|
|
270
338
|
|
|
271
339
|
for (const m of code.matchAll(/['"](\/live-tokens[^'"]*)['"]\s*:/g)) {
|
|
272
340
|
add('reserved-route', m.index, `route '${m[1]}' is inside the reserved /live-tokens/* namespace`);
|
|
@@ -315,8 +383,8 @@ function checkFile(file, text, vocab, root) {
|
|
|
315
383
|
'unknown-token',
|
|
316
384
|
at(m.index),
|
|
317
385
|
isContractToken(name)
|
|
318
|
-
? `${name}
|
|
319
|
-
: `${name} is not a
|
|
386
|
+
? `${name} has the shape of a design token but no longer exists. Check tokens.css for a rename`
|
|
387
|
+
: `${name} is not a design token, a semantic property, or declared in this file`,
|
|
320
388
|
);
|
|
321
389
|
}
|
|
322
390
|
|
|
@@ -328,25 +396,38 @@ function checkFile(file, text, vocab, root) {
|
|
|
328
396
|
// inside one is not the page's value.
|
|
329
397
|
const painted = stripVarFallbacks(value);
|
|
330
398
|
if (!TEXT_AXES.includes(prop) && hasColorLiteral(painted)) {
|
|
331
|
-
add('color-literal', at(index), `${prop}: ${value}. Use a
|
|
399
|
+
add('color-literal', at(index), `${prop}: ${value}. Use a design token.`);
|
|
332
400
|
continue;
|
|
333
401
|
}
|
|
334
402
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
(
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
403
|
+
if (TEXT_AXES.includes(prop) || prop === 'font') {
|
|
404
|
+
const axis = [...painted.matchAll(/var\(\s*(--[a-z0-9-]+)/g)]
|
|
405
|
+
.map((m) => m[1])
|
|
406
|
+
.find((name) => SINGLE_AXIS_TOKEN.test(name));
|
|
407
|
+
if (axis) {
|
|
408
|
+
add(
|
|
409
|
+
'raw-text-axis',
|
|
410
|
+
at(index),
|
|
411
|
+
`${prop}: ${value}. ${axis} is one axis. Set every axis from one text style bundle (--heading-*, --body-*, --editorial-*, --code-*).`,
|
|
412
|
+
);
|
|
413
|
+
continue;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// Of the literals only absolute type values are a finding. `em`, `%`,
|
|
417
|
+
// and a unitless line-height are relative to the inherited type, so
|
|
418
|
+
// they ride whatever the theme sets rather than overriding it.
|
|
419
|
+
if (
|
|
420
|
+
!value.includes('var(') &&
|
|
421
|
+
!/^(inherit|initial|unset|normal)$/.test(value) &&
|
|
422
|
+
/\d(px|rem|pt)\b|^[a-z"']/i.test(value)
|
|
423
|
+
) {
|
|
424
|
+
add(
|
|
425
|
+
'raw-text-axis',
|
|
426
|
+
at(index),
|
|
427
|
+
`${prop}: ${value}. Set type from a text style bundle (--heading-*, --body-*, --editorial-*, --code-*).`,
|
|
428
|
+
);
|
|
429
|
+
continue;
|
|
430
|
+
}
|
|
350
431
|
}
|
|
351
432
|
|
|
352
433
|
if (THEMED_GEOMETRY.test(prop) && hasDimensionLiteral(painted)) {
|
package/bin/cli.mjs
CHANGED
|
@@ -4,25 +4,27 @@
|
|
|
4
4
|
// create <dir> Scaffold a new app that depends on this package.
|
|
5
5
|
// setup-claude [--force] Copy bundled Claude Code skills into ./.claude/skills/.
|
|
6
6
|
// components [id] List every component the project has, shipped and its own, with props and tokens.
|
|
7
|
-
// tokens [--
|
|
7
|
+
// tokens [--scale <name>] List every design token by scale, with its value.
|
|
8
8
|
// report The project as facts: tokens read, components used, findings by rule. Always exits 0.
|
|
9
9
|
// check-component [id] Validate a component (or every authored one) against the create-component skill contract.
|
|
10
|
-
// check-page [paths...] Validate pages against the
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
// set-
|
|
10
|
+
// check-page [paths...] Validate pages against the create-page skill contract.
|
|
11
|
+
// set-colors <colors> Build the color identity from 10 OKLCH base colors, into the open buffer.
|
|
12
|
+
// set-geometry <ops> Apply radius/padding/gap/border-width ops to the open buffer.
|
|
13
|
+
// set-type <pairing> Bind Google Fonts families to the theme's font stacks.
|
|
14
|
+
// save-theme <name> Compose the live state into themes/<slug>.json and open it.
|
|
14
15
|
// migrate [...] Reconcile tokens.css, the data tree, and route references.
|
|
15
16
|
|
|
16
17
|
import { cpSync, existsSync, mkdirSync, readdirSync, statSync, writeSync } from 'node:fs';
|
|
17
18
|
import { dirname, join, resolve } from 'node:path';
|
|
18
19
|
import { fileURLToPath } from 'node:url';
|
|
19
20
|
import process from 'node:process';
|
|
20
|
-
import { COMPONENT_RULES, checkComponent, discoverComponents, formatReport } from './check-component.mjs';
|
|
21
|
+
import { COMPONENT_RULES, COMPONENT_RULE_FIX, checkComponent, discoverComponents, formatReport } from './check-component.mjs';
|
|
21
22
|
import { PAGE_RULES, checkPages, discoverPages } from './check-page.mjs';
|
|
22
23
|
import { describeComponents, describeTokens, formatComponents, formatTokens } from './lib/catalogue.mjs';
|
|
23
24
|
import { buildReport, formatReport as formatProjectReport } from './lib/report.mjs';
|
|
24
25
|
import { loadVocabulary } from './lib/tokenVocabulary.mjs';
|
|
25
26
|
import {
|
|
27
|
+
applyCoverageSeverity,
|
|
26
28
|
applySeverity,
|
|
27
29
|
countBySeverity,
|
|
28
30
|
formatFindings,
|
|
@@ -38,38 +40,45 @@ import {
|
|
|
38
40
|
} from './migrate.mjs';
|
|
39
41
|
import { runMigrateRoutes, formatRouteResult } from './migrate-routes.mjs';
|
|
40
42
|
import { runCreate, formatCreateResult } from './create.mjs';
|
|
41
|
-
import {
|
|
42
|
-
import {
|
|
43
|
-
import {
|
|
43
|
+
import { runSetColors, formatSetColorsResult } from './set-colors.mjs';
|
|
44
|
+
import { runSetGeometry, formatSetGeometryResult } from './set-geometry.mjs';
|
|
45
|
+
import { runSetType, formatSetTypeResult } from './set-type.mjs';
|
|
46
|
+
import { runSaveTheme, formatSaveThemeResult } from './save-theme.mjs';
|
|
44
47
|
|
|
45
48
|
const USAGE = `Usage: npx @motion-proto/live-tokens <command> [options]
|
|
46
49
|
|
|
47
50
|
Commands:
|
|
48
51
|
create <dir> [--force] Scaffold a new Svelte + Vite app wired up with
|
|
49
|
-
live-tokens (editor, components,
|
|
52
|
+
live-tokens (editor, components, design tokens)
|
|
50
53
|
setup-claude [--force] Install bundled Claude Code skills into ./.claude/skills/
|
|
51
54
|
components [id] [--json] List every component the project has, shipped and
|
|
52
55
|
its own (src/system/components plus any
|
|
53
|
-
"componentDirs" in live-tokens.config.json)
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
tokens [--
|
|
57
|
-
List every
|
|
58
|
-
declares, by
|
|
56
|
+
"componentDirs" in live-tokens.config.json). With
|
|
57
|
+
an id, that component's props, variants, tokens,
|
|
58
|
+
and defaults
|
|
59
|
+
tokens [--scale <name>] [--json]
|
|
60
|
+
List every design token the project's tokens.css
|
|
61
|
+
declares, by scale, with its value
|
|
59
62
|
report [--json] The project as facts: pending migrations, tokens
|
|
60
63
|
each component declares and reads, which page
|
|
61
64
|
renders which component, and both checkers'
|
|
62
65
|
findings by rule under the project's severities
|
|
63
|
-
and under --strict.
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
against the live-tokens-create-component contract
|
|
67
|
-
|
|
66
|
+
and under --strict. Always exits 0
|
|
67
|
+
check-component [id] [--tests]
|
|
68
|
+
Validate <id>'s runtime, editor, and registration
|
|
69
|
+
against the live-tokens-create-component contract.
|
|
70
|
+
--tests also runs the registry contract under
|
|
71
|
+
vitest and the component contract suites under
|
|
72
|
+
Playwright, reporting coverage by rule. Needs
|
|
73
|
+
@playwright/test, vitest, and happy-dom; a
|
|
74
|
+
missing one is a tests-not-installed finding
|
|
75
|
+
naming the install command
|
|
76
|
+
check-page [paths...] Validate pages against the live-tokens-create-page
|
|
68
77
|
contract: catalogue components only, and every CSS
|
|
69
|
-
value a
|
|
78
|
+
value a design token. Checks every page under src/
|
|
70
79
|
when given no paths.
|
|
71
80
|
|
|
72
|
-
|
|
81
|
+
check-component and check-page also accept:
|
|
73
82
|
--json Machine-readable findings, for a skill to iterate
|
|
74
83
|
against until the exit code is 0
|
|
75
84
|
--strict Treat warnings as errors
|
|
@@ -77,40 +86,47 @@ Both check commands accept:
|
|
|
77
86
|
(or set "checks": { "rules": {...} } in
|
|
78
87
|
live-tokens.config.json; "checks": { "exclude":
|
|
79
88
|
[...] } drops paths from discovery entirely)
|
|
80
|
-
|
|
81
|
-
Build
|
|
82
|
-
(see the live-tokens-
|
|
83
|
-
enforce AA contrast on derived text
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
component aliases) carries forward from the live
|
|
91
|
-
look, or from theme <name> with --carry-from.
|
|
92
|
-
adjust <ops.json> [--dry-run]
|
|
89
|
+
set-colors <base-colors.json> [--dry-run]
|
|
90
|
+
Build the theme's whole color identity from 10
|
|
91
|
+
OKLCH base colors (see the live-tokens-set-colors
|
|
92
|
+
skill) and enforce AA contrast on the derived text
|
|
93
|
+
tokens. Reads the live colors and type and writes
|
|
94
|
+
the result to the colors-and-type buffer. Run
|
|
95
|
+
save-theme to keep it as a theme. Fonts and every
|
|
96
|
+
override no palette owns carry forward. --dry-run
|
|
97
|
+
prints the contrast report without writing.
|
|
98
|
+
set-geometry <ops.json> [--dry-run]
|
|
93
99
|
Move radius, padding, gap, and border-width
|
|
94
100
|
aliases along their token scales (see the
|
|
95
|
-
live-tokens-
|
|
101
|
+
live-tokens-set-geometry skill). Reads each
|
|
96
102
|
component's live config and writes the result to
|
|
97
|
-
that component's
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
set-
|
|
103
|
+
that component's buffer. Run save-theme to keep it
|
|
104
|
+
as a theme. --dry-run prints the report without
|
|
105
|
+
writing.
|
|
106
|
+
set-type <pairing.json> [--dry-run] [--no-verify]
|
|
101
107
|
Bind Google Fonts families to --font-display,
|
|
102
108
|
--font-sans, --font-serif, --font-mono and
|
|
103
109
|
--font-editorial (see
|
|
104
|
-
the live-tokens-
|
|
110
|
+
the live-tokens-set-type skill). Each family is
|
|
105
111
|
verified against the Google Fonts API and the URL
|
|
106
|
-
is negotiated from the weights it
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
+
is negotiated from the weights it has. Writes the
|
|
113
|
+
result to the colors-and-type buffer. Run
|
|
114
|
+
save-theme to keep it as a theme. --dry-run prints
|
|
115
|
+
the report without writing. --no-verify skips the
|
|
116
|
+
network and requires an explicit URL per family.
|
|
117
|
+
save-theme <name> [--no-activate] [--dry-run]
|
|
118
|
+
Compose the live state (the buffers, the open
|
|
119
|
+
theme under them, the shipped defaults under that)
|
|
120
|
+
into themes/<slug>.json and load it, which clears
|
|
121
|
+
the buffers. With no buffer it saves a copy of the
|
|
122
|
+
open theme under the new name. Loading never
|
|
123
|
+
changes what the site ships. Adopt in the editor
|
|
124
|
+
does that. --no-activate writes the theme and does
|
|
125
|
+
not load it, so a set of themes comes off one
|
|
126
|
+
starting theme. --dry-run prints the report
|
|
127
|
+
without writing.
|
|
112
128
|
migrate [--check] [--write] [--tokens <path>]
|
|
113
|
-
Reconcile
|
|
129
|
+
Reconcile the project with the installed package:
|
|
114
130
|
applies additive tokens.css migrations, moves a
|
|
115
131
|
pre-0.48 data tree onto the current directory
|
|
116
132
|
names, heals what the retired pointer files named,
|
|
@@ -150,7 +166,7 @@ if (!command || command === '--help' || command === '-h') {
|
|
|
150
166
|
|
|
151
167
|
const pkgRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
152
168
|
|
|
153
|
-
if (command === 'create'
|
|
169
|
+
if (command === 'create') {
|
|
154
170
|
const targetArg = rest.find((a) => !a.startsWith('-'));
|
|
155
171
|
if (!targetArg) {
|
|
156
172
|
fail(`Usage: npx @motion-proto/live-tokens create <project-directory>`);
|
|
@@ -166,14 +182,19 @@ if (command === 'create' || command === 'init') {
|
|
|
166
182
|
}
|
|
167
183
|
}
|
|
168
184
|
|
|
169
|
-
function reportChecks(label, findings, checked, rules, opts) {
|
|
170
|
-
const
|
|
185
|
+
function reportChecks(label, findings, checked, rules, opts, { coverage, hardFailure, fixes } = {}) {
|
|
186
|
+
const checksConfig = readChecksConfig(process.cwd());
|
|
187
|
+
const resolved = applySeverity(findings, rules, opts, checksConfig, fixes ?? {});
|
|
188
|
+
const resolvedCoverage = coverage ? applyCoverageSeverity(coverage, rules, opts, checksConfig) : coverage;
|
|
171
189
|
console.log(
|
|
172
190
|
opts.json
|
|
173
|
-
? toJson(resolved, { label, checked })
|
|
191
|
+
? toJson(resolved, { label, checked, coverage: resolvedCoverage })
|
|
174
192
|
: formatFindings(resolved, { label, checked }),
|
|
175
193
|
);
|
|
176
|
-
|
|
194
|
+
// Decision 2: a missing tool or a setup failure under --tests is an error
|
|
195
|
+
// even if a project silenced its rule id, since silencing it would read as
|
|
196
|
+
// "the tests passed" rather than "the tests did not run".
|
|
197
|
+
process.exit(countBySeverity(resolved).errors === 0 && !hardFailure ? 0 : 1);
|
|
177
198
|
}
|
|
178
199
|
|
|
179
200
|
if (command === 'components') {
|
|
@@ -187,14 +208,14 @@ if (command === 'components') {
|
|
|
187
208
|
|
|
188
209
|
if (command === 'tokens') {
|
|
189
210
|
const opts = parseCheckFlags(rest);
|
|
190
|
-
const at = opts.rest.indexOf('--
|
|
191
|
-
const
|
|
211
|
+
const at = opts.rest.indexOf('--scale');
|
|
212
|
+
const scale = at >= 0 ? opts.rest[at + 1] : undefined;
|
|
192
213
|
const desc = describeTokens(loadVocabulary());
|
|
193
|
-
if (
|
|
214
|
+
if (scale && !desc.scales.some((s) => s.scale === scale)) fail(formatTokens(desc, { scale }));
|
|
194
215
|
writeOut(
|
|
195
216
|
opts.json
|
|
196
|
-
? JSON.stringify(
|
|
197
|
-
: formatTokens(desc, {
|
|
217
|
+
? JSON.stringify(scale ? desc.scales.find((s) => s.scale === scale) : desc, null, 2)
|
|
218
|
+
: formatTokens(desc, { scale }),
|
|
198
219
|
);
|
|
199
220
|
process.exit(0);
|
|
200
221
|
}
|
|
@@ -220,18 +241,28 @@ if (command === 'report') {
|
|
|
220
241
|
if (command === 'check-component') {
|
|
221
242
|
const opts = parseCheckFlags(rest);
|
|
222
243
|
const ids = opts.rest.length > 0 ? [opts.rest[0]] : discoverComponents();
|
|
223
|
-
if (ids.length === 0) {
|
|
244
|
+
if (ids.length === 0 && !opts.tests) {
|
|
224
245
|
console.log('✓ check-component: no component authored under src/system/components yet.');
|
|
225
246
|
process.exit(0);
|
|
226
247
|
}
|
|
227
248
|
const results = ids.map((id) => [id, checkComponent(id)]);
|
|
228
|
-
if (ids.length === 1 && !opts.json && !opts.strict && opts.off.length + opts.warn.length + opts.error.length === 0) {
|
|
249
|
+
if (!opts.tests && ids.length === 1 && !opts.json && !opts.strict && opts.off.length + opts.warn.length + opts.error.length === 0) {
|
|
229
250
|
const [id, result] = results[0];
|
|
230
251
|
console.log(formatReport(id, result));
|
|
231
252
|
process.exit(result.errors.length === 0 ? 0 : 1);
|
|
232
253
|
}
|
|
233
|
-
const label = ids.length === 1 ? `check-component ${ids[0]}` :
|
|
234
|
-
|
|
254
|
+
const label = ids.length === 1 ? `check-component ${ids[0]}${opts.tests ? ' --tests' : ''}` : `check-component${opts.tests ? ' --tests' : ''}`;
|
|
255
|
+
if (!opts.tests) {
|
|
256
|
+
reportChecks(label, results.flatMap(([, r]) => r.findings), ids.length, COMPONENT_RULES, opts, { fixes: COMPONENT_RULE_FIX });
|
|
257
|
+
}
|
|
258
|
+
const { hasHardFailure, runContractTests } = await import('./contractRunner.mjs');
|
|
259
|
+
const testOutcome = await runContractTests(opts.rest[0], { root: process.cwd() });
|
|
260
|
+
const findings = [...results.flatMap(([, r]) => r.findings), ...testOutcome.findings];
|
|
261
|
+
reportChecks(label, findings, Math.max(ids.length, 1), COMPONENT_RULES, opts, {
|
|
262
|
+
fixes: COMPONENT_RULE_FIX,
|
|
263
|
+
coverage: testOutcome.coverage,
|
|
264
|
+
hardFailure: hasHardFailure(testOutcome.findings),
|
|
265
|
+
});
|
|
235
266
|
}
|
|
236
267
|
|
|
237
268
|
if (command === 'check-page') {
|
|
@@ -241,72 +272,97 @@ if (command === 'check-page') {
|
|
|
241
272
|
reportChecks('check-page', findings, checked, PAGE_RULES, opts);
|
|
242
273
|
}
|
|
243
274
|
|
|
244
|
-
if (command === '
|
|
245
|
-
const
|
|
246
|
-
if (!
|
|
247
|
-
fail(`Usage: npx @motion-proto/live-tokens
|
|
275
|
+
if (command === 'set-colors') {
|
|
276
|
+
const baseColorsPath = rest.find((a) => !a.startsWith('-'));
|
|
277
|
+
if (!baseColorsPath) {
|
|
278
|
+
fail(`Usage: npx @motion-proto/live-tokens set-colors <base-colors.json> [--dry-run]`);
|
|
279
|
+
}
|
|
280
|
+
if (rest.includes('--no-activate')) {
|
|
281
|
+
fail(
|
|
282
|
+
`set-colors has no --no-activate: it edits the open buffer, which is what the page already runs. ` +
|
|
283
|
+
`Nothing is activated until save-theme, which takes the flag.`,
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
if (rest.includes('--carry-from')) {
|
|
287
|
+
fail(
|
|
288
|
+
`set-colors has no --carry-from: it reads the live theme and edits it in place, so a second theme ` +
|
|
289
|
+
`already starts from the first. Run save-theme --no-activate between themes.`,
|
|
290
|
+
);
|
|
248
291
|
}
|
|
249
292
|
try {
|
|
250
|
-
const
|
|
251
|
-
|
|
252
|
-
if (carryIdx !== -1 && !carryFrom) fail(`--carry-from requires a theme name`);
|
|
253
|
-
const result = await runGenerateTheme({
|
|
254
|
-
briefPath,
|
|
255
|
-
activate: !rest.includes('--no-activate'),
|
|
293
|
+
const result = await runSetColors({
|
|
294
|
+
baseColorsPath,
|
|
256
295
|
dryRun: rest.includes('--dry-run'),
|
|
257
|
-
carryFrom,
|
|
258
296
|
});
|
|
259
|
-
console.log(
|
|
297
|
+
console.log(formatSetColorsResult(result));
|
|
260
298
|
process.exit(result.report.failures.length === 0 ? 0 : 1);
|
|
261
299
|
} catch (err) {
|
|
262
|
-
fail(`
|
|
300
|
+
fail(`set-colors failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
263
301
|
}
|
|
264
302
|
}
|
|
265
303
|
|
|
266
|
-
if (command === '
|
|
304
|
+
if (command === 'set-geometry') {
|
|
267
305
|
const opsPath = rest.find((a) => !a.startsWith('-'));
|
|
268
306
|
if (!opsPath) {
|
|
269
|
-
fail(`Usage: npx @motion-proto/live-tokens
|
|
307
|
+
fail(`Usage: npx @motion-proto/live-tokens set-geometry <ops.json> [--dry-run]`);
|
|
270
308
|
}
|
|
271
309
|
if (rest.includes('--no-activate')) {
|
|
272
310
|
fail(
|
|
273
|
-
`
|
|
311
|
+
`set-geometry has no --no-activate: it edits the open buffer, which is what the page already runs. ` +
|
|
274
312
|
`Drop the flag and re-run.`,
|
|
275
313
|
);
|
|
276
314
|
}
|
|
277
315
|
try {
|
|
278
|
-
const result = await
|
|
316
|
+
const result = await runSetGeometry({
|
|
279
317
|
opsPath,
|
|
280
318
|
dryRun: rest.includes('--dry-run'),
|
|
281
319
|
});
|
|
282
|
-
console.log(
|
|
320
|
+
console.log(formatSetGeometryResult(result));
|
|
283
321
|
process.exit(0);
|
|
284
322
|
} catch (err) {
|
|
285
|
-
fail(`
|
|
323
|
+
fail(`set-geometry failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
286
324
|
}
|
|
287
325
|
}
|
|
288
326
|
|
|
289
|
-
if (command === 'set-
|
|
290
|
-
const
|
|
291
|
-
if (!
|
|
292
|
-
fail(`Usage: npx @motion-proto/live-tokens set-
|
|
327
|
+
if (command === 'set-type') {
|
|
328
|
+
const pairingPath = rest.find((a) => !a.startsWith('-'));
|
|
329
|
+
if (!pairingPath) {
|
|
330
|
+
fail(`Usage: npx @motion-proto/live-tokens set-type <pairing.json> [--dry-run] [--no-verify]`);
|
|
293
331
|
}
|
|
294
332
|
if (rest.includes('--no-activate')) {
|
|
295
333
|
fail(
|
|
296
|
-
`set-
|
|
334
|
+
`set-type has no --no-activate: it edits the open buffer, which is what the page already runs. ` +
|
|
297
335
|
`Drop the flag and re-run.`,
|
|
298
336
|
);
|
|
299
337
|
}
|
|
300
338
|
try {
|
|
301
|
-
const result = await
|
|
302
|
-
|
|
339
|
+
const result = await runSetType({
|
|
340
|
+
pairingPath,
|
|
303
341
|
dryRun: rest.includes('--dry-run'),
|
|
304
342
|
verify: !rest.includes('--no-verify'),
|
|
305
343
|
});
|
|
306
|
-
console.log(
|
|
344
|
+
console.log(formatSetTypeResult(result));
|
|
345
|
+
process.exit(0);
|
|
346
|
+
} catch (err) {
|
|
347
|
+
fail(`set-type failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
if (command === 'save-theme') {
|
|
352
|
+
const name = rest.find((a) => !a.startsWith('-'));
|
|
353
|
+
if (!name) {
|
|
354
|
+
fail(`Usage: npx @motion-proto/live-tokens save-theme <name> [--no-activate] [--dry-run]`);
|
|
355
|
+
}
|
|
356
|
+
try {
|
|
357
|
+
const result = await runSaveTheme({
|
|
358
|
+
name,
|
|
359
|
+
activate: !rest.includes('--no-activate'),
|
|
360
|
+
dryRun: rest.includes('--dry-run'),
|
|
361
|
+
});
|
|
362
|
+
console.log(formatSaveThemeResult(result));
|
|
307
363
|
process.exit(0);
|
|
308
364
|
} catch (err) {
|
|
309
|
-
fail(`
|
|
365
|
+
fail(`save-theme failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
310
366
|
}
|
|
311
367
|
}
|
|
312
368
|
|
|
@@ -385,15 +441,16 @@ for (const skill of skills) {
|
|
|
385
441
|
installed++;
|
|
386
442
|
}
|
|
387
443
|
|
|
388
|
-
console.log(`\n${installed} installed, ${skipped} skipped
|
|
444
|
+
console.log(`\n${installed} installed, ${skipped} skipped, in ${destSkills}`);
|
|
389
445
|
|
|
390
446
|
const SAMPLE_PROMPTS = {
|
|
391
|
-
'live-tokens-
|
|
447
|
+
'live-tokens-create-page': 'build a pricing page using live-tokens components',
|
|
392
448
|
'live-tokens-pick-component': "what's the difference between TabBar and SegmentedControl?",
|
|
393
449
|
'live-tokens-create-component': 'author a new Toggle component for my live-tokens project',
|
|
394
|
-
'live-tokens-
|
|
395
|
-
'live-tokens-
|
|
396
|
-
'live-tokens-
|
|
450
|
+
'live-tokens-create-theme': 'make me a bright and cheerful theme',
|
|
451
|
+
'live-tokens-set-colors': 'give me a cooler palette, same fonts',
|
|
452
|
+
'live-tokens-set-type': 'pair some fonts for this theme',
|
|
453
|
+
'live-tokens-set-geometry': 'make the buttons pill shaped',
|
|
397
454
|
'live-tokens-fix-findings': 'make check:design pass',
|
|
398
455
|
'live-tokens-check-compliance': 'check this project against the design system',
|
|
399
456
|
};
|
|
@@ -405,6 +462,6 @@ const installedSamples = skills
|
|
|
405
462
|
if (installedSamples.length > 0) {
|
|
406
463
|
console.log(`\nIn Claude Code, prompts like these auto-trigger the matching skill:`);
|
|
407
464
|
for (const [skill, prompt] of installedSamples) {
|
|
408
|
-
console.log(`
|
|
465
|
+
console.log(` "${prompt}"\n ${skill}`);
|
|
409
466
|
}
|
|
410
467
|
}
|