@atomixstudio/mcp 0.1.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 +325 -0
- package/data/component-tokens-snapshot.json +659 -0
- package/data/tenants/default.json +73 -0
- package/dist/index.d.ts +202 -0
- package/dist/index.js +2974 -0
- package/dist/index.js.map +1 -0
- package/package.json +50 -0
- package/scripts/sync-component-tokens.cjs +974 -0
- package/scripts/sync-component-tokens.js +678 -0
- package/src/ai-rules-generator.ts +1144 -0
- package/src/component-tokens.ts +702 -0
- package/src/index.ts +1155 -0
- package/src/tenant-store.ts +436 -0
- package/src/tokens.ts +208 -0
- package/src/user-tokens.ts +268 -0
- package/src/utils.ts +465 -0
- package/tests/stress-test.cjs +907 -0
- package/tsconfig.json +21 -0
- package/tsup.config.ts +16 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,2974 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
5
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
|
+
import {
|
|
7
|
+
CallToolRequestSchema,
|
|
8
|
+
ListToolsRequestSchema,
|
|
9
|
+
ListResourcesRequestSchema,
|
|
10
|
+
ReadResourceRequestSchema
|
|
11
|
+
} from "@modelcontextprotocol/sdk/types.js";
|
|
12
|
+
|
|
13
|
+
// src/tokens.ts
|
|
14
|
+
import { fileURLToPath } from "url";
|
|
15
|
+
import { dirname, join } from "path";
|
|
16
|
+
var __filename = fileURLToPath(import.meta.url);
|
|
17
|
+
var __dirname = dirname(__filename);
|
|
18
|
+
var atomixPath = join(__dirname, "../../atomix/dist/index.mjs");
|
|
19
|
+
var loadedPrimitives = null;
|
|
20
|
+
async function loadPrimitives() {
|
|
21
|
+
if (loadedPrimitives) return loadedPrimitives;
|
|
22
|
+
try {
|
|
23
|
+
const module = await import(atomixPath);
|
|
24
|
+
loadedPrimitives = module.primitives;
|
|
25
|
+
return loadedPrimitives;
|
|
26
|
+
} catch (error) {
|
|
27
|
+
console.error(`Failed to load @atomix/tokens from ${atomixPath}:`, error);
|
|
28
|
+
console.error("Falling back to inline primitives...");
|
|
29
|
+
loadedPrimitives = FALLBACK_PRIMITIVES;
|
|
30
|
+
return FALLBACK_PRIMITIVES;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
var primitives = {};
|
|
34
|
+
loadPrimitives().then((p) => {
|
|
35
|
+
primitives = p;
|
|
36
|
+
});
|
|
37
|
+
var TOKEN_CATEGORIES = [
|
|
38
|
+
"colors",
|
|
39
|
+
"typography",
|
|
40
|
+
"spacing",
|
|
41
|
+
"sizing",
|
|
42
|
+
"shadows",
|
|
43
|
+
"radius",
|
|
44
|
+
"motion",
|
|
45
|
+
"zIndex",
|
|
46
|
+
"borders"
|
|
47
|
+
];
|
|
48
|
+
var FALLBACK_PRIMITIVES = {
|
|
49
|
+
colors: {
|
|
50
|
+
static: {
|
|
51
|
+
brand: {
|
|
52
|
+
primary: "#007061",
|
|
53
|
+
primaryLight: "#00A389",
|
|
54
|
+
primaryDark: "#005A4D",
|
|
55
|
+
primaryForeground: "#FFFFFF"
|
|
56
|
+
},
|
|
57
|
+
white: "#FFFFFF",
|
|
58
|
+
black: "#000000"
|
|
59
|
+
},
|
|
60
|
+
modes: {
|
|
61
|
+
light: {
|
|
62
|
+
bgPage: "#FFFFFF",
|
|
63
|
+
bgSurface: "#FFFFFF",
|
|
64
|
+
bgMuted: "#F5F5F5",
|
|
65
|
+
textPrimary: "#171717",
|
|
66
|
+
textSecondary: "#525252",
|
|
67
|
+
textMuted: "#A3A3A3",
|
|
68
|
+
// Icon colors (derived from brand/text)
|
|
69
|
+
iconBrand: "#007061",
|
|
70
|
+
// = brand.primary
|
|
71
|
+
iconStrong: "#171717",
|
|
72
|
+
// = textPrimary
|
|
73
|
+
iconSubtle: "#525252",
|
|
74
|
+
// = textSecondary
|
|
75
|
+
iconDisabled: "#A3A3A3",
|
|
76
|
+
// = textMuted
|
|
77
|
+
borderPrimary: "#E5E5E5"
|
|
78
|
+
},
|
|
79
|
+
dark: {
|
|
80
|
+
bgPage: "#0A0A0A",
|
|
81
|
+
bgSurface: "#1A1A1A",
|
|
82
|
+
bgMuted: "#262626",
|
|
83
|
+
textPrimary: "#FAFAFA",
|
|
84
|
+
textSecondary: "#A3A3A3",
|
|
85
|
+
textMuted: "#737373",
|
|
86
|
+
// Icon colors (derived from brand/text)
|
|
87
|
+
iconBrand: "#007061",
|
|
88
|
+
// = brand.primary
|
|
89
|
+
iconStrong: "#FAFAFA",
|
|
90
|
+
// = textPrimary
|
|
91
|
+
iconSubtle: "#A3A3A3",
|
|
92
|
+
// = textSecondary
|
|
93
|
+
iconDisabled: "#737373",
|
|
94
|
+
// = textMuted
|
|
95
|
+
borderPrimary: "#404040"
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
scales: {
|
|
99
|
+
green: {
|
|
100
|
+
50: "#E6F5F2",
|
|
101
|
+
500: "#007061",
|
|
102
|
+
900: "#002E28"
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
typography: {
|
|
107
|
+
fontFamily: {
|
|
108
|
+
sans: "Inter, system-ui, sans-serif",
|
|
109
|
+
mono: "JetBrains Mono, monospace"
|
|
110
|
+
},
|
|
111
|
+
fontSize: {
|
|
112
|
+
xs: "0.75rem",
|
|
113
|
+
sm: "0.875rem",
|
|
114
|
+
md: "1rem",
|
|
115
|
+
lg: "1.125rem",
|
|
116
|
+
xl: "1.25rem"
|
|
117
|
+
},
|
|
118
|
+
fontWeight: {
|
|
119
|
+
regular: 400,
|
|
120
|
+
medium: 500,
|
|
121
|
+
semibold: 600,
|
|
122
|
+
bold: 700
|
|
123
|
+
},
|
|
124
|
+
lineHeight: {
|
|
125
|
+
tight: 1.25,
|
|
126
|
+
normal: 1.5,
|
|
127
|
+
relaxed: 1.625
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
spacing: {
|
|
131
|
+
scale: {
|
|
132
|
+
xs: "0.25rem",
|
|
133
|
+
sm: "0.5rem",
|
|
134
|
+
md: "1rem",
|
|
135
|
+
lg: "1.5rem",
|
|
136
|
+
xl: "2rem"
|
|
137
|
+
},
|
|
138
|
+
inset: {
|
|
139
|
+
xs: "0.25rem",
|
|
140
|
+
sm: "0.5rem",
|
|
141
|
+
md: "1rem",
|
|
142
|
+
lg: "1.5rem"
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
sizing: {
|
|
146
|
+
button: {
|
|
147
|
+
sm: { height: "32px" },
|
|
148
|
+
md: { height: "40px" },
|
|
149
|
+
lg: { height: "48px" }
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
shadows: {
|
|
153
|
+
elevation: {
|
|
154
|
+
none: "none",
|
|
155
|
+
sm: "0 1px 2px rgba(0, 0, 0, 0.05)",
|
|
156
|
+
md: "0 4px 6px rgba(0, 0, 0, 0.1)",
|
|
157
|
+
lg: "0 10px 15px rgba(0, 0, 0, 0.1)"
|
|
158
|
+
},
|
|
159
|
+
focus: {
|
|
160
|
+
ring: "0 0 0 2px var(--atomix-brand)"
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
radius: {
|
|
164
|
+
scale: {
|
|
165
|
+
none: "0",
|
|
166
|
+
sm: "0.25rem",
|
|
167
|
+
md: "0.5rem",
|
|
168
|
+
lg: "0.75rem",
|
|
169
|
+
xl: "1rem",
|
|
170
|
+
full: "9999px"
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
motion: {
|
|
174
|
+
duration: {
|
|
175
|
+
instant: "0ms",
|
|
176
|
+
fast: "150ms",
|
|
177
|
+
normal: "200ms",
|
|
178
|
+
slow: "300ms"
|
|
179
|
+
},
|
|
180
|
+
easing: {
|
|
181
|
+
ease: "cubic-bezier(0.4, 0, 0.2, 1)",
|
|
182
|
+
easeIn: "cubic-bezier(0.4, 0, 1, 1)",
|
|
183
|
+
easeOut: "cubic-bezier(0, 0, 0.2, 1)"
|
|
184
|
+
}
|
|
185
|
+
},
|
|
186
|
+
zIndex: {
|
|
187
|
+
dropdown: 1e3,
|
|
188
|
+
modal: 1100,
|
|
189
|
+
tooltip: 1200
|
|
190
|
+
},
|
|
191
|
+
borders: {
|
|
192
|
+
width: {
|
|
193
|
+
none: "0",
|
|
194
|
+
thin: "1px",
|
|
195
|
+
medium: "2px"
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
// src/utils.ts
|
|
201
|
+
function getTokenByPath(obj, path) {
|
|
202
|
+
const parts = path.split(".");
|
|
203
|
+
let current = obj;
|
|
204
|
+
for (const part of parts) {
|
|
205
|
+
if (current === null || current === void 0) return void 0;
|
|
206
|
+
if (typeof current !== "object") return void 0;
|
|
207
|
+
current = current[part];
|
|
208
|
+
}
|
|
209
|
+
return current;
|
|
210
|
+
}
|
|
211
|
+
function listTokensInCategory(primitives3, category, subcategory) {
|
|
212
|
+
let base = primitives3[category];
|
|
213
|
+
if (!base) return {};
|
|
214
|
+
if (subcategory) {
|
|
215
|
+
const subParts = subcategory.split(".");
|
|
216
|
+
for (const part of subParts) {
|
|
217
|
+
if (typeof base !== "object" || base === null) return {};
|
|
218
|
+
base = base[part];
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
if (typeof base !== "object" || base === null) {
|
|
222
|
+
return { [subcategory || category]: base };
|
|
223
|
+
}
|
|
224
|
+
return flattenTokens(base);
|
|
225
|
+
}
|
|
226
|
+
function flattenTokens(obj, prefix = "") {
|
|
227
|
+
const result = {};
|
|
228
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
229
|
+
const path = prefix ? `${prefix}.${key}` : key;
|
|
230
|
+
if (value !== null && typeof value === "object" && !Array.isArray(value)) {
|
|
231
|
+
Object.assign(result, flattenTokens(value, path));
|
|
232
|
+
} else {
|
|
233
|
+
result[path] = value;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return result;
|
|
237
|
+
}
|
|
238
|
+
function getTokenCategories() {
|
|
239
|
+
return [...TOKEN_CATEGORIES];
|
|
240
|
+
}
|
|
241
|
+
function getCssVariableName(path) {
|
|
242
|
+
const dashPath = path.replace(/\./g, "-").replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
|
|
243
|
+
return `--atomix-${dashPath}`;
|
|
244
|
+
}
|
|
245
|
+
function getTokenMetadata(path) {
|
|
246
|
+
if (path.match(/^colors\.scales\./)) {
|
|
247
|
+
return {
|
|
248
|
+
tier: "primitive",
|
|
249
|
+
mutable: false,
|
|
250
|
+
guidance: "Raw color palette. Use semantic colors (colors.modes.*) in components instead."
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
if (path.match(/^colors\.scales\.(black|white|green)Alpha\./)) {
|
|
254
|
+
return {
|
|
255
|
+
tier: "primitive",
|
|
256
|
+
mutable: false,
|
|
257
|
+
guidance: "Alpha transparency scale. Reference only for overlays/effects."
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
if (path.match(/^spacing\.scale\./)) {
|
|
261
|
+
return {
|
|
262
|
+
tier: "primitive",
|
|
263
|
+
mutable: false,
|
|
264
|
+
guidance: "Spacing scale values. Use semantic spacing keys (xs, sm, md, lg) in components."
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
if (path.match(/^spacing\.(inset|stack|inline|gap)\./)) {
|
|
268
|
+
return {
|
|
269
|
+
tier: "primitive",
|
|
270
|
+
mutable: false,
|
|
271
|
+
guidance: "Spacing presets derived from scale. Reference only."
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
if (path.match(/^typography\.(fontSize|fontWeight|lineHeight|lineHeightPx|letterSpacing|paragraphSpacing)\./)) {
|
|
275
|
+
return {
|
|
276
|
+
tier: "primitive",
|
|
277
|
+
mutable: false,
|
|
278
|
+
guidance: "Raw typography values. Use typeSets (title-lg, text-normal-regular) in components."
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
if (path.match(/^radius\.scale\./)) {
|
|
282
|
+
return {
|
|
283
|
+
tier: "primitive",
|
|
284
|
+
mutable: false,
|
|
285
|
+
guidance: "Border radius scale. Use semantic radius (radius.semantic.*) or scale keys in components."
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
if (path.match(/^borders\.width\./)) {
|
|
289
|
+
return {
|
|
290
|
+
tier: "primitive",
|
|
291
|
+
mutable: false,
|
|
292
|
+
guidance: "Border width scale. Use semantic border keys in components."
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
if (path.match(/^shadows\.elevation\./)) {
|
|
296
|
+
return {
|
|
297
|
+
tier: "primitive",
|
|
298
|
+
mutable: false,
|
|
299
|
+
guidance: "Elevation shadow values. Use elevation keys (sm, md, lg) in components."
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
if (path.match(/^motion\.(duration|easing)\./)) {
|
|
303
|
+
return {
|
|
304
|
+
tier: "primitive",
|
|
305
|
+
mutable: false,
|
|
306
|
+
guidance: "Motion primitives. Use semantic motion presets (motion.semantic.*) when available."
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
if (path.match(/^zIndex\.scale\./)) {
|
|
310
|
+
return {
|
|
311
|
+
tier: "primitive",
|
|
312
|
+
mutable: false,
|
|
313
|
+
guidance: "Z-index scale. Use semantic z-index (zIndex.semantic.*) in components."
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
if (path.match(/^sizing\./)) {
|
|
317
|
+
return {
|
|
318
|
+
tier: "primitive",
|
|
319
|
+
mutable: false,
|
|
320
|
+
guidance: "Component sizing values. Reference only for layout calculations."
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
if (path.match(/^colors\.modes\.(light|dark)\./)) {
|
|
324
|
+
return {
|
|
325
|
+
tier: "semantic",
|
|
326
|
+
mutable: true,
|
|
327
|
+
editVia: "designer",
|
|
328
|
+
guidance: "Semantic color for theming. Use this in components. Editable via Atomix Designer."
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
if (path.match(/^colors\.adaptive\./)) {
|
|
332
|
+
return {
|
|
333
|
+
tier: "semantic",
|
|
334
|
+
mutable: true,
|
|
335
|
+
editVia: "designer",
|
|
336
|
+
guidance: "Adaptive feedback color (error, warning, success, info). Use for validation states."
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
if (path.match(/^colors\.static\.brand/)) {
|
|
340
|
+
return {
|
|
341
|
+
tier: "semantic",
|
|
342
|
+
mutable: false,
|
|
343
|
+
// Brand colors are locked
|
|
344
|
+
guidance: "Brand identity color. Use for primary brand elements. Protected from modification."
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
if (path.match(/^colors\.static\.(white|black|transparent)/)) {
|
|
348
|
+
return {
|
|
349
|
+
tier: "primitive",
|
|
350
|
+
mutable: false,
|
|
351
|
+
guidance: "Static utility color. Use for absolute white/black when needed."
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
if (path.match(/^radius\.semantic\./)) {
|
|
355
|
+
return {
|
|
356
|
+
tier: "semantic",
|
|
357
|
+
mutable: true,
|
|
358
|
+
editVia: "designer",
|
|
359
|
+
guidance: "Semantic border radius for component types. Use this in component styling."
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
if (path.match(/^borders\.semantic\./)) {
|
|
363
|
+
return {
|
|
364
|
+
tier: "semantic",
|
|
365
|
+
mutable: true,
|
|
366
|
+
editVia: "designer",
|
|
367
|
+
guidance: "Semantic border width for component types. Use this in component styling."
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
if (path.match(/^motion\.semantic\./)) {
|
|
371
|
+
return {
|
|
372
|
+
tier: "semantic",
|
|
373
|
+
mutable: true,
|
|
374
|
+
editVia: "designer",
|
|
375
|
+
guidance: "Semantic animation preset. Use for consistent motion patterns."
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
if (path.match(/^zIndex\.semantic\./)) {
|
|
379
|
+
return {
|
|
380
|
+
tier: "semantic",
|
|
381
|
+
mutable: true,
|
|
382
|
+
editVia: "designer",
|
|
383
|
+
guidance: "Semantic z-index for UI layers. Use for proper stacking order."
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
if (path.match(/^shadows\.focus\./)) {
|
|
387
|
+
return {
|
|
388
|
+
tier: "semantic",
|
|
389
|
+
mutable: true,
|
|
390
|
+
editVia: "designer",
|
|
391
|
+
guidance: "Focus ring styles for accessibility. Use for keyboard focus indicators."
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
if (path.match(/^typography\.typeSets\./)) {
|
|
395
|
+
return {
|
|
396
|
+
tier: "semantic",
|
|
397
|
+
mutable: true,
|
|
398
|
+
editVia: "designer",
|
|
399
|
+
guidance: "Composed typography style. Use these for consistent text styling."
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
if (path.match(/^typography\.fontFamily\./)) {
|
|
403
|
+
return {
|
|
404
|
+
tier: "semantic",
|
|
405
|
+
mutable: true,
|
|
406
|
+
editVia: "designer",
|
|
407
|
+
guidance: "Font family selection. Use 'sans', 'mono', or 'display' keys."
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
if (path.match(/^typography\.textStyles\./)) {
|
|
411
|
+
return {
|
|
412
|
+
tier: "semantic",
|
|
413
|
+
mutable: true,
|
|
414
|
+
editVia: "designer",
|
|
415
|
+
guidance: "Complete text style definition. Use for consistent typography."
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
return {
|
|
419
|
+
tier: "primitive",
|
|
420
|
+
mutable: false,
|
|
421
|
+
guidance: "Token classification unknown. Treat as read-only reference."
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// src/component-tokens.ts
|
|
426
|
+
var COMPONENT_TOKENS = {
|
|
427
|
+
"button": {
|
|
428
|
+
"description": "Interactive button component with multiple variants and sizes",
|
|
429
|
+
"sizes": {
|
|
430
|
+
"sm": {
|
|
431
|
+
"tokens": {
|
|
432
|
+
"top": "xs",
|
|
433
|
+
"right": "sm",
|
|
434
|
+
"bottom": "xs",
|
|
435
|
+
"left": "sm",
|
|
436
|
+
"borderRadius": "radius.scale.lg",
|
|
437
|
+
"typeSet": "typography.typeSets.text-small-bold"
|
|
438
|
+
}
|
|
439
|
+
},
|
|
440
|
+
"padding": {
|
|
441
|
+
"tokens": {
|
|
442
|
+
"top": "xs",
|
|
443
|
+
"right": "sm",
|
|
444
|
+
"bottom": "xs",
|
|
445
|
+
"left": "sm",
|
|
446
|
+
"borderRadius": "radius.scale.lg",
|
|
447
|
+
"typeSet": "typography.typeSets.text-small-bold"
|
|
448
|
+
}
|
|
449
|
+
},
|
|
450
|
+
"md": {
|
|
451
|
+
"tokens": {
|
|
452
|
+
"top": "sm",
|
|
453
|
+
"right": "lg",
|
|
454
|
+
"bottom": "sm",
|
|
455
|
+
"left": "lg",
|
|
456
|
+
"borderRadius": "radius.scale.4xl",
|
|
457
|
+
"typeSet": "typography.typeSets.text-normal-bold"
|
|
458
|
+
}
|
|
459
|
+
},
|
|
460
|
+
"lg": {
|
|
461
|
+
"tokens": {
|
|
462
|
+
"top": "sm",
|
|
463
|
+
"right": "lg",
|
|
464
|
+
"bottom": "sm",
|
|
465
|
+
"left": "lg",
|
|
466
|
+
"borderRadius": "radius.scale.4xl",
|
|
467
|
+
"typeSet": "typography.typeSets.text-large-bold"
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
},
|
|
472
|
+
"card": {
|
|
473
|
+
"description": "Container component for grouping related content",
|
|
474
|
+
"variants": {
|
|
475
|
+
"default": {
|
|
476
|
+
"description": "default variant",
|
|
477
|
+
"tokens": {
|
|
478
|
+
"background": "colors.modes.{mode}.bgSurface",
|
|
479
|
+
"borderColor": "colors.modes.{mode}.borderStrong",
|
|
480
|
+
"borderWidth": "sm",
|
|
481
|
+
"borderRadius": "xl",
|
|
482
|
+
"shadow": "none",
|
|
483
|
+
"titleColor": "colors.modes.{mode}.textPrimary",
|
|
484
|
+
"bodyColor": "colors.modes.{mode}.textSecondary",
|
|
485
|
+
"eyebrowColor": "colors.modes.{mode}.textMuted",
|
|
486
|
+
"interaction": "elevation",
|
|
487
|
+
"hoverShadow": "elevation-lg",
|
|
488
|
+
"hoverTranslateY": "-2px",
|
|
489
|
+
"hoverBorderColor": "colors.modes.{mode}.borderStrong"
|
|
490
|
+
}
|
|
491
|
+
},
|
|
492
|
+
"elevated": {
|
|
493
|
+
"description": "elevated variant",
|
|
494
|
+
"tokens": {
|
|
495
|
+
"background": "colors.modes.{mode}.bgSurface",
|
|
496
|
+
"borderColor": "colors.modes.{mode}.borderPrimary",
|
|
497
|
+
"borderWidth": "sm",
|
|
498
|
+
"borderRadius": "2xl",
|
|
499
|
+
"shadow": "elevation-md",
|
|
500
|
+
"titleColor": "colors.modes.{mode}.textPrimary",
|
|
501
|
+
"bodyColor": "colors.modes.{mode}.textSecondary",
|
|
502
|
+
"eyebrowColor": "colors.modes.{mode}.textMuted",
|
|
503
|
+
"interaction": "elevation",
|
|
504
|
+
"hoverShadow": "elevation-lg",
|
|
505
|
+
"hoverTranslateY": "-2px",
|
|
506
|
+
"hoverBorderColor": "transparent"
|
|
507
|
+
}
|
|
508
|
+
},
|
|
509
|
+
"outlined": {
|
|
510
|
+
"description": "outlined variant",
|
|
511
|
+
"tokens": {
|
|
512
|
+
"background": "transparent",
|
|
513
|
+
"borderColor": "colors.modes.{mode}.borderSecondary",
|
|
514
|
+
"borderWidth": "lg",
|
|
515
|
+
"borderRadius": "2xl",
|
|
516
|
+
"shadow": "none",
|
|
517
|
+
"titleColor": "colors.modes.{mode}.textPrimary",
|
|
518
|
+
"bodyColor": "colors.modes.{mode}.textSecondary",
|
|
519
|
+
"eyebrowColor": "colors.modes.{mode}.textMuted",
|
|
520
|
+
"interaction": "border",
|
|
521
|
+
"hoverShadow": "none",
|
|
522
|
+
"hoverTranslateY": "0",
|
|
523
|
+
"hoverBorderColor": "colors.modes.{mode}.borderStrong"
|
|
524
|
+
}
|
|
525
|
+
},
|
|
526
|
+
"ghost": {
|
|
527
|
+
"description": "ghost variant",
|
|
528
|
+
"tokens": {
|
|
529
|
+
"background": "transparent",
|
|
530
|
+
"borderColor": "transparent",
|
|
531
|
+
"borderWidth": "none",
|
|
532
|
+
"borderRadius": "xl",
|
|
533
|
+
"shadow": "none",
|
|
534
|
+
"titleColor": "colors.modes.{mode}.textPrimary",
|
|
535
|
+
"bodyColor": "colors.modes.{mode}.textMuted",
|
|
536
|
+
"eyebrowColor": "colors.modes.{mode}.textMuted",
|
|
537
|
+
"interaction": "none",
|
|
538
|
+
"hoverShadow": "none",
|
|
539
|
+
"hoverTranslateY": "0",
|
|
540
|
+
"hoverBorderColor": "transparent"
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
},
|
|
544
|
+
"sizes": {
|
|
545
|
+
"sm": {
|
|
546
|
+
"tokens": {
|
|
547
|
+
"top": "lg",
|
|
548
|
+
"right": "xl",
|
|
549
|
+
"bottom": "lg",
|
|
550
|
+
"left": "xl",
|
|
551
|
+
"headingSize": "sm"
|
|
552
|
+
}
|
|
553
|
+
},
|
|
554
|
+
"padding": {
|
|
555
|
+
"tokens": {
|
|
556
|
+
"top": "lg",
|
|
557
|
+
"right": "xl",
|
|
558
|
+
"bottom": "lg",
|
|
559
|
+
"left": "xl",
|
|
560
|
+
"headingSize": "sm"
|
|
561
|
+
}
|
|
562
|
+
},
|
|
563
|
+
"md": {
|
|
564
|
+
"tokens": {
|
|
565
|
+
"top": "xl",
|
|
566
|
+
"right": "2xl",
|
|
567
|
+
"bottom": "xl",
|
|
568
|
+
"left": "2xl",
|
|
569
|
+
"headingSize": "md"
|
|
570
|
+
}
|
|
571
|
+
},
|
|
572
|
+
"lg": {
|
|
573
|
+
"tokens": {
|
|
574
|
+
"top": "2xl",
|
|
575
|
+
"right": "3xl",
|
|
576
|
+
"bottom": "2xl",
|
|
577
|
+
"left": "3xl",
|
|
578
|
+
"headingSize": "lg"
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
},
|
|
582
|
+
"shared": {
|
|
583
|
+
"titleFontFamily": "typography.fontFamily.sans",
|
|
584
|
+
"bodyFontFamily": "typography.fontFamily.sans"
|
|
585
|
+
}
|
|
586
|
+
},
|
|
587
|
+
"input": {
|
|
588
|
+
"description": "Text input field component with validation states",
|
|
589
|
+
"variants": {
|
|
590
|
+
"default": {
|
|
591
|
+
"description": "default variant",
|
|
592
|
+
"tokens": {
|
|
593
|
+
"borderWidth": "sm",
|
|
594
|
+
"borderColor": "colors.modes.{mode}.borderPrimary",
|
|
595
|
+
"borderColorFocus": "colors.modes.{mode}.borderStrong",
|
|
596
|
+
"helperTextColor": "colors.modes.{mode}.textMuted"
|
|
597
|
+
}
|
|
598
|
+
},
|
|
599
|
+
"error": {
|
|
600
|
+
"description": "error variant",
|
|
601
|
+
"tokens": {
|
|
602
|
+
"borderWidth": "md",
|
|
603
|
+
"borderColor": "colors.adaptive.error.{mode}.border",
|
|
604
|
+
"borderColorFocus": "colors.adaptive.error.{mode}.border",
|
|
605
|
+
"helperTextColor": "colors.adaptive.error.{mode}.text"
|
|
606
|
+
}
|
|
607
|
+
},
|
|
608
|
+
"success": {
|
|
609
|
+
"description": "success variant",
|
|
610
|
+
"tokens": {
|
|
611
|
+
"borderWidth": "md",
|
|
612
|
+
"borderColor": "colors.modes.{mode}.ring",
|
|
613
|
+
"borderColorFocus": "colors.modes.{mode}.ring",
|
|
614
|
+
"helperTextColor": "colors.adaptive.success.{mode}.text"
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
},
|
|
618
|
+
"sizes": {
|
|
619
|
+
"sm": {
|
|
620
|
+
"tokens": {
|
|
621
|
+
"fieldHeight": "32px",
|
|
622
|
+
"helperTypeSet": "helper-text",
|
|
623
|
+
"borderRadius": "radius.scale.lg",
|
|
624
|
+
"top": "xs",
|
|
625
|
+
"right": "md",
|
|
626
|
+
"bottom": "xs",
|
|
627
|
+
"left": "md"
|
|
628
|
+
}
|
|
629
|
+
},
|
|
630
|
+
"padding": {
|
|
631
|
+
"tokens": {
|
|
632
|
+
"top": "xs",
|
|
633
|
+
"right": "md",
|
|
634
|
+
"bottom": "xs",
|
|
635
|
+
"left": "md"
|
|
636
|
+
}
|
|
637
|
+
},
|
|
638
|
+
"md": {
|
|
639
|
+
"tokens": {
|
|
640
|
+
"fieldHeight": "40px",
|
|
641
|
+
"helperTypeSet": "helper-text",
|
|
642
|
+
"borderRadius": "radius.scale.xl",
|
|
643
|
+
"top": "sm",
|
|
644
|
+
"right": "md",
|
|
645
|
+
"bottom": "sm",
|
|
646
|
+
"left": "md"
|
|
647
|
+
}
|
|
648
|
+
},
|
|
649
|
+
"lg": {
|
|
650
|
+
"tokens": {
|
|
651
|
+
"fieldHeight": "48px",
|
|
652
|
+
"helperTypeSet": "helper-text",
|
|
653
|
+
"borderRadius": "radius.scale.2xl",
|
|
654
|
+
"top": "xl",
|
|
655
|
+
"right": "lg",
|
|
656
|
+
"bottom": "xl",
|
|
657
|
+
"left": "lg"
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
},
|
|
662
|
+
"select": {
|
|
663
|
+
"description": "Unified text field component supporting input, select, and textarea",
|
|
664
|
+
"variants": {
|
|
665
|
+
"default": {
|
|
666
|
+
"description": "default variant",
|
|
667
|
+
"tokens": {
|
|
668
|
+
"borderWidth": "md",
|
|
669
|
+
"borderColor": "colors.modes.{mode}.borderPrimary",
|
|
670
|
+
"borderColorFocus": "colors.modes.{mode}.borderSecondary",
|
|
671
|
+
"helperTextColor": "colors.modes.{mode}.textMuted"
|
|
672
|
+
}
|
|
673
|
+
},
|
|
674
|
+
"error": {
|
|
675
|
+
"description": "error variant",
|
|
676
|
+
"tokens": {
|
|
677
|
+
"borderWidth": "md",
|
|
678
|
+
"borderColor": "colors.adaptive.error.{mode}.border",
|
|
679
|
+
"borderColorFocus": "colors.adaptive.error.{mode}.border",
|
|
680
|
+
"helperTextColor": "colors.adaptive.error.{mode}.text"
|
|
681
|
+
}
|
|
682
|
+
},
|
|
683
|
+
"success": {
|
|
684
|
+
"description": "success variant",
|
|
685
|
+
"tokens": {
|
|
686
|
+
"borderWidth": "md",
|
|
687
|
+
"borderColor": "colors.modes.{mode}.ring",
|
|
688
|
+
"borderColorFocus": "colors.modes.{mode}.ring",
|
|
689
|
+
"helperTextColor": "colors.adaptive.success.{mode}.text"
|
|
690
|
+
}
|
|
691
|
+
},
|
|
692
|
+
"disabled": {
|
|
693
|
+
"description": "disabled variant",
|
|
694
|
+
"tokens": {
|
|
695
|
+
"borderWidth": "sm",
|
|
696
|
+
"borderColor": "colors.modes.{mode}.borderSecondary",
|
|
697
|
+
"borderColorFocus": "colors.modes.{mode}.borderSecondary",
|
|
698
|
+
"helperTextColor": "colors.modes.{mode}.textDisabled"
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
},
|
|
702
|
+
"sizes": {
|
|
703
|
+
"sm": {
|
|
704
|
+
"tokens": {
|
|
705
|
+
"fieldHeight": "32px",
|
|
706
|
+
"helperTypeSet": "helper-text",
|
|
707
|
+
"borderRadius": "radius.scale.lg",
|
|
708
|
+
"top": "xs",
|
|
709
|
+
"right": "md",
|
|
710
|
+
"bottom": "xs",
|
|
711
|
+
"left": "md"
|
|
712
|
+
}
|
|
713
|
+
},
|
|
714
|
+
"padding": {
|
|
715
|
+
"tokens": {
|
|
716
|
+
"top": "xs",
|
|
717
|
+
"right": "md",
|
|
718
|
+
"bottom": "xs",
|
|
719
|
+
"left": "md"
|
|
720
|
+
}
|
|
721
|
+
},
|
|
722
|
+
"md": {
|
|
723
|
+
"tokens": {
|
|
724
|
+
"fieldHeight": "44px",
|
|
725
|
+
"helperTypeSet": "helper-text",
|
|
726
|
+
"borderRadius": "none",
|
|
727
|
+
"top": "sm",
|
|
728
|
+
"right": "md",
|
|
729
|
+
"bottom": "sm",
|
|
730
|
+
"left": "md"
|
|
731
|
+
}
|
|
732
|
+
},
|
|
733
|
+
"lg": {
|
|
734
|
+
"tokens": {
|
|
735
|
+
"fieldHeight": "48px",
|
|
736
|
+
"helperTypeSet": "helper-text",
|
|
737
|
+
"borderRadius": "radius.scale.2xl",
|
|
738
|
+
"top": "xl",
|
|
739
|
+
"right": "lg",
|
|
740
|
+
"bottom": "xl",
|
|
741
|
+
"left": "lg"
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
},
|
|
746
|
+
"dialog": {
|
|
747
|
+
"description": "Modal dialog for focused interactions",
|
|
748
|
+
"variants": {
|
|
749
|
+
"default": {
|
|
750
|
+
"description": "default variant",
|
|
751
|
+
"tokens": {
|
|
752
|
+
"titleColor": "colors.modes.{mode}.textPrimary",
|
|
753
|
+
"bodyColor": "colors.modes.{mode}.textSecondary",
|
|
754
|
+
"contentAlign": "center",
|
|
755
|
+
"eyebrowColor": "colors.modes.{mode}.textMuted",
|
|
756
|
+
"buttonAlign": "center"
|
|
757
|
+
}
|
|
758
|
+
},
|
|
759
|
+
"with-footer": {
|
|
760
|
+
"description": "with-footer variant",
|
|
761
|
+
"tokens": {
|
|
762
|
+
"titleColor": "colors.modes.{mode}.textPrimary",
|
|
763
|
+
"bodyColor": "colors.modes.{mode}.textSecondary",
|
|
764
|
+
"contentAlign": "left",
|
|
765
|
+
"eyebrowColor": "colors.modes.{mode}.textMuted",
|
|
766
|
+
"buttonAlign": "space-between"
|
|
767
|
+
}
|
|
768
|
+
},
|
|
769
|
+
"minimal": {
|
|
770
|
+
"description": "minimal variant",
|
|
771
|
+
"tokens": {
|
|
772
|
+
"titleColor": "colors.modes.{mode}.textPrimary",
|
|
773
|
+
"bodyColor": "colors.modes.{mode}.textMuted",
|
|
774
|
+
"contentAlign": "center",
|
|
775
|
+
"eyebrowColor": "colors.modes.{mode}.textMuted",
|
|
776
|
+
"buttonAlign": "center"
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
},
|
|
780
|
+
"sizes": {
|
|
781
|
+
"sm": {
|
|
782
|
+
"tokens": {
|
|
783
|
+
"headingSize": "sm",
|
|
784
|
+
"top": "xl",
|
|
785
|
+
"right": "xl",
|
|
786
|
+
"bottom": "xl",
|
|
787
|
+
"left": "xl",
|
|
788
|
+
"buttonSize": "sm"
|
|
789
|
+
}
|
|
790
|
+
},
|
|
791
|
+
"padding": {
|
|
792
|
+
"tokens": {
|
|
793
|
+
"top": "xl",
|
|
794
|
+
"right": "xl",
|
|
795
|
+
"bottom": "xl",
|
|
796
|
+
"left": "xl",
|
|
797
|
+
"buttonSize": "sm"
|
|
798
|
+
}
|
|
799
|
+
},
|
|
800
|
+
"md": {
|
|
801
|
+
"tokens": {
|
|
802
|
+
"headingSize": "md",
|
|
803
|
+
"top": "xl",
|
|
804
|
+
"right": "xl",
|
|
805
|
+
"bottom": "xl",
|
|
806
|
+
"left": "xl",
|
|
807
|
+
"buttonSize": "md"
|
|
808
|
+
}
|
|
809
|
+
},
|
|
810
|
+
"lg": {
|
|
811
|
+
"tokens": {
|
|
812
|
+
"headingSize": "lg",
|
|
813
|
+
"top": "xl",
|
|
814
|
+
"right": "xl",
|
|
815
|
+
"bottom": "xl",
|
|
816
|
+
"left": "xl",
|
|
817
|
+
"buttonSize": "lg"
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
},
|
|
821
|
+
"shared": {
|
|
822
|
+
"titleFontFamily": "typography.fontFamily.sans",
|
|
823
|
+
"bodyFontFamily": "typography.fontFamily.sans"
|
|
824
|
+
}
|
|
825
|
+
},
|
|
826
|
+
"heading": {
|
|
827
|
+
"description": "Typography component for titles, descriptions, and eyebrows",
|
|
828
|
+
"variants": {
|
|
829
|
+
"title-only": {
|
|
830
|
+
"description": "title-only variant",
|
|
831
|
+
"tokens": {
|
|
832
|
+
"eyebrowColor": "colors.modes.{mode}.textMuted",
|
|
833
|
+
"titleColor": "colors.modes.{mode}.textPrimary",
|
|
834
|
+
"descriptionColor": "colors.modes.{mode}.textSecondary",
|
|
835
|
+
"textAlign": "left",
|
|
836
|
+
"eyebrowGap": "xs",
|
|
837
|
+
"descriptionGap": "sm",
|
|
838
|
+
"footerGap": "sm"
|
|
839
|
+
}
|
|
840
|
+
},
|
|
841
|
+
"title-description": {
|
|
842
|
+
"description": "title-description variant",
|
|
843
|
+
"tokens": {
|
|
844
|
+
"eyebrowColor": "colors.modes.{mode}.textMuted",
|
|
845
|
+
"titleColor": "colors.modes.{mode}.textPrimary",
|
|
846
|
+
"descriptionColor": "colors.modes.{mode}.textSecondary",
|
|
847
|
+
"textAlign": "left",
|
|
848
|
+
"eyebrowGap": "xs",
|
|
849
|
+
"descriptionGap": "xs",
|
|
850
|
+
"footerGap": "sm"
|
|
851
|
+
}
|
|
852
|
+
},
|
|
853
|
+
"full": {
|
|
854
|
+
"description": "full variant",
|
|
855
|
+
"tokens": {
|
|
856
|
+
"eyebrowColor": "colors.modes.{mode}.textSecondary",
|
|
857
|
+
"titleColor": "colors.modes.{mode}.textPrimary",
|
|
858
|
+
"descriptionColor": "colors.modes.{mode}.textSecondary",
|
|
859
|
+
"textAlign": "left",
|
|
860
|
+
"eyebrowGap": "xs",
|
|
861
|
+
"descriptionGap": "xs",
|
|
862
|
+
"footerGap": "sm"
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
},
|
|
866
|
+
"sizes": {
|
|
867
|
+
"sm": {
|
|
868
|
+
"tokens": {
|
|
869
|
+
"eyebrowTypeSet": "typography.typeSets.title-sm",
|
|
870
|
+
"titleTypeSet": "typography.typeSets.title-md",
|
|
871
|
+
"descriptionTypeSet": "typography.typeSets.text-normal-regular"
|
|
872
|
+
}
|
|
873
|
+
},
|
|
874
|
+
"md": {
|
|
875
|
+
"tokens": {
|
|
876
|
+
"eyebrowTypeSet": "typography.typeSets.title-sm",
|
|
877
|
+
"titleTypeSet": "typography.typeSets.title-lg",
|
|
878
|
+
"descriptionTypeSet": "typography.typeSets.text-normal-regular"
|
|
879
|
+
}
|
|
880
|
+
},
|
|
881
|
+
"lg": {
|
|
882
|
+
"tokens": {
|
|
883
|
+
"eyebrowTypeSet": "typography.typeSets.title-sm",
|
|
884
|
+
"titleTypeSet": "typography.typeSets.title-2xl",
|
|
885
|
+
"descriptionTypeSet": "typography.typeSets.text-normal-regular"
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
},
|
|
889
|
+
"shared": {
|
|
890
|
+
"fontFamily": "typography.fontFamily.sans"
|
|
891
|
+
}
|
|
892
|
+
},
|
|
893
|
+
"selectionControls": {
|
|
894
|
+
"description": "Selection control components: checkbox, radio, and toggle switch",
|
|
895
|
+
"variants": {
|
|
896
|
+
"checkbox": {
|
|
897
|
+
"description": "checkbox variant",
|
|
898
|
+
"tokens": {
|
|
899
|
+
"background": "colors.modes.{mode}.bgMuted",
|
|
900
|
+
"backgroundChecked": "colors.modes.{mode}.actionPrimary",
|
|
901
|
+
"backgroundDisabled": "colors.modes.{mode}.actionSecondary",
|
|
902
|
+
"backgroundError": "colors.modes.{mode}.bgMuted",
|
|
903
|
+
"borderWidth": "md",
|
|
904
|
+
"borderWidthError": "md",
|
|
905
|
+
"borderWidthDisabled": "md",
|
|
906
|
+
"borderColor": "colors.modes.{mode}.borderStrong",
|
|
907
|
+
"borderColorChecked": "transparent",
|
|
908
|
+
"borderColorDisabled": "colors.modes.{mode}.borderSecondary",
|
|
909
|
+
"borderColorError": "colors.adaptive.error.{mode}.border",
|
|
910
|
+
"indicatorColor": "colors.static.white",
|
|
911
|
+
"labelColor": "colors.modes.{mode}.textPrimary",
|
|
912
|
+
"interaction": "subtle"
|
|
913
|
+
}
|
|
914
|
+
},
|
|
915
|
+
"radio": {
|
|
916
|
+
"description": "radio variant",
|
|
917
|
+
"tokens": {
|
|
918
|
+
"background": "colors.modes.{mode}.bgMuted",
|
|
919
|
+
"backgroundChecked": "colors.modes.{mode}.actionPrimary",
|
|
920
|
+
"backgroundDisabled": "colors.modes.{mode}.actionSecondary",
|
|
921
|
+
"backgroundError": "colors.modes.{mode}.bgMuted",
|
|
922
|
+
"borderWidth": "md",
|
|
923
|
+
"borderWidthError": "md",
|
|
924
|
+
"borderWidthDisabled": "md",
|
|
925
|
+
"borderColor": "colors.modes.{mode}.borderStrong",
|
|
926
|
+
"borderColorChecked": "transparent",
|
|
927
|
+
"borderColorDisabled": "colors.modes.{mode}.borderSecondary",
|
|
928
|
+
"borderColorError": "colors.adaptive.error.{mode}.border",
|
|
929
|
+
"indicatorColor": "colors.static.white",
|
|
930
|
+
"labelColor": "colors.modes.{mode}.textPrimary",
|
|
931
|
+
"interaction": "subtle"
|
|
932
|
+
}
|
|
933
|
+
},
|
|
934
|
+
"toggle": {
|
|
935
|
+
"description": "toggle variant",
|
|
936
|
+
"tokens": {
|
|
937
|
+
"background": "colors.modes.{mode}.bgMuted",
|
|
938
|
+
"backgroundChecked": "colors.modes.{mode}.actionPrimary",
|
|
939
|
+
"backgroundDisabled": "colors.modes.{mode}.actionSecondary",
|
|
940
|
+
"backgroundError": "colors.modes.{mode}.bgMuted",
|
|
941
|
+
"borderWidth": "md",
|
|
942
|
+
"borderWidthError": "md",
|
|
943
|
+
"borderWidthDisabled": "md",
|
|
944
|
+
"borderColor": "colors.modes.{mode}.borderStrong",
|
|
945
|
+
"borderColorChecked": "transparent",
|
|
946
|
+
"borderColorDisabled": "colors.modes.{mode}.borderSecondary",
|
|
947
|
+
"borderColorError": "colors.adaptive.error.{mode}.border",
|
|
948
|
+
"indicatorColor": "colors.static.white",
|
|
949
|
+
"labelColor": "colors.modes.{mode}.textPrimary",
|
|
950
|
+
"interaction": "press"
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
},
|
|
954
|
+
"sizes": {
|
|
955
|
+
"md": {
|
|
956
|
+
"tokens": {
|
|
957
|
+
"controlSize": "20px",
|
|
958
|
+
"labelTypeSet": "typography.typeSets.text-normal-regular",
|
|
959
|
+
"gap": "spacing.scale.sm",
|
|
960
|
+
"borderRadius": "radius.scale.lg"
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
},
|
|
965
|
+
"checkbox": {
|
|
966
|
+
"description": "Checkbox selection control",
|
|
967
|
+
"variants": {
|
|
968
|
+
"default": {
|
|
969
|
+
"description": "checkbox variant",
|
|
970
|
+
"tokens": {
|
|
971
|
+
"background": "colors.modes.{mode}.bgMuted",
|
|
972
|
+
"backgroundChecked": "colors.modes.{mode}.actionPrimary",
|
|
973
|
+
"backgroundDisabled": "colors.modes.{mode}.actionSecondary",
|
|
974
|
+
"backgroundError": "colors.modes.{mode}.bgMuted",
|
|
975
|
+
"borderWidth": "md",
|
|
976
|
+
"borderWidthError": "md",
|
|
977
|
+
"borderWidthDisabled": "md",
|
|
978
|
+
"borderColor": "colors.modes.{mode}.borderStrong",
|
|
979
|
+
"borderColorChecked": "transparent",
|
|
980
|
+
"borderColorDisabled": "colors.modes.{mode}.borderSecondary",
|
|
981
|
+
"borderColorError": "colors.adaptive.error.{mode}.border",
|
|
982
|
+
"indicatorColor": "colors.static.white",
|
|
983
|
+
"labelColor": "colors.modes.{mode}.textPrimary",
|
|
984
|
+
"interaction": "subtle"
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
},
|
|
988
|
+
"sizes": {
|
|
989
|
+
"md": {
|
|
990
|
+
"tokens": {
|
|
991
|
+
"controlSize": "20px",
|
|
992
|
+
"labelTypeSet": "typography.typeSets.text-normal-regular",
|
|
993
|
+
"gap": "spacing.scale.sm",
|
|
994
|
+
"borderRadius": "radius.scale.lg"
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
},
|
|
998
|
+
"shared": {
|
|
999
|
+
"transitionDuration": "motion.duration.fast",
|
|
1000
|
+
"focusRing": "shadows.focus.ring"
|
|
1001
|
+
}
|
|
1002
|
+
},
|
|
1003
|
+
"radio": {
|
|
1004
|
+
"description": "Radio selection control",
|
|
1005
|
+
"variants": {
|
|
1006
|
+
"default": {
|
|
1007
|
+
"description": "radio variant",
|
|
1008
|
+
"tokens": {
|
|
1009
|
+
"background": "colors.modes.{mode}.bgMuted",
|
|
1010
|
+
"backgroundChecked": "colors.modes.{mode}.actionPrimary",
|
|
1011
|
+
"backgroundDisabled": "colors.modes.{mode}.actionSecondary",
|
|
1012
|
+
"backgroundError": "colors.modes.{mode}.bgMuted",
|
|
1013
|
+
"borderWidth": "md",
|
|
1014
|
+
"borderWidthError": "md",
|
|
1015
|
+
"borderWidthDisabled": "md",
|
|
1016
|
+
"borderColor": "colors.modes.{mode}.borderStrong",
|
|
1017
|
+
"borderColorChecked": "transparent",
|
|
1018
|
+
"borderColorDisabled": "colors.modes.{mode}.borderSecondary",
|
|
1019
|
+
"borderColorError": "colors.adaptive.error.{mode}.border",
|
|
1020
|
+
"indicatorColor": "colors.static.white",
|
|
1021
|
+
"labelColor": "colors.modes.{mode}.textPrimary",
|
|
1022
|
+
"interaction": "subtle"
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
},
|
|
1026
|
+
"sizes": {
|
|
1027
|
+
"md": {
|
|
1028
|
+
"tokens": {
|
|
1029
|
+
"controlSize": "20px",
|
|
1030
|
+
"labelTypeSet": "typography.typeSets.text-normal-regular",
|
|
1031
|
+
"gap": "spacing.scale.sm",
|
|
1032
|
+
"borderRadius": "radius.scale.lg"
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
},
|
|
1036
|
+
"shared": {
|
|
1037
|
+
"transitionDuration": "motion.duration.fast",
|
|
1038
|
+
"focusRing": "shadows.focus.ring"
|
|
1039
|
+
}
|
|
1040
|
+
},
|
|
1041
|
+
"toggle": {
|
|
1042
|
+
"description": "Toggle selection control",
|
|
1043
|
+
"variants": {
|
|
1044
|
+
"default": {
|
|
1045
|
+
"description": "toggle variant",
|
|
1046
|
+
"tokens": {
|
|
1047
|
+
"background": "colors.modes.{mode}.bgMuted",
|
|
1048
|
+
"backgroundChecked": "colors.modes.{mode}.actionPrimary",
|
|
1049
|
+
"backgroundDisabled": "colors.modes.{mode}.actionSecondary",
|
|
1050
|
+
"backgroundError": "colors.modes.{mode}.bgMuted",
|
|
1051
|
+
"borderWidth": "md",
|
|
1052
|
+
"borderWidthError": "md",
|
|
1053
|
+
"borderWidthDisabled": "md",
|
|
1054
|
+
"borderColor": "colors.modes.{mode}.borderStrong",
|
|
1055
|
+
"borderColorChecked": "transparent",
|
|
1056
|
+
"borderColorDisabled": "colors.modes.{mode}.borderSecondary",
|
|
1057
|
+
"borderColorError": "colors.adaptive.error.{mode}.border",
|
|
1058
|
+
"indicatorColor": "colors.static.white",
|
|
1059
|
+
"labelColor": "colors.modes.{mode}.textPrimary",
|
|
1060
|
+
"interaction": "press"
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
},
|
|
1064
|
+
"sizes": {
|
|
1065
|
+
"md": {
|
|
1066
|
+
"tokens": {
|
|
1067
|
+
"controlSize": "20px",
|
|
1068
|
+
"labelTypeSet": "typography.typeSets.text-normal-regular",
|
|
1069
|
+
"gap": "spacing.scale.sm",
|
|
1070
|
+
"borderRadius": "radius.scale.lg"
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
},
|
|
1074
|
+
"shared": {
|
|
1075
|
+
"transitionDuration": "motion.duration.fast",
|
|
1076
|
+
"focusRing": "shadows.focus.ring"
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
};
|
|
1080
|
+
|
|
1081
|
+
// src/user-tokens.ts
|
|
1082
|
+
var DEFAULT_BASE_URL = "https://atomixstudio.eu";
|
|
1083
|
+
async function fetchUserDesignSystem(options) {
|
|
1084
|
+
const { dsId, apiKey, baseUrl = DEFAULT_BASE_URL } = options;
|
|
1085
|
+
try {
|
|
1086
|
+
const headers = {
|
|
1087
|
+
"Content-Type": "application/json"
|
|
1088
|
+
};
|
|
1089
|
+
if (apiKey) {
|
|
1090
|
+
headers["Authorization"] = `Bearer ${apiKey}`;
|
|
1091
|
+
}
|
|
1092
|
+
const tokensResponse = await fetch(`${baseUrl}/api/ds/${dsId}/tokens`, {
|
|
1093
|
+
method: "GET",
|
|
1094
|
+
headers
|
|
1095
|
+
});
|
|
1096
|
+
if (!tokensResponse.ok) {
|
|
1097
|
+
const error = await tokensResponse.text();
|
|
1098
|
+
return {
|
|
1099
|
+
success: false,
|
|
1100
|
+
error: `Failed to fetch tokens: ${tokensResponse.status} ${error}`
|
|
1101
|
+
};
|
|
1102
|
+
}
|
|
1103
|
+
const tokensData = await tokensResponse.json();
|
|
1104
|
+
const meta = "meta" in tokensData && tokensData.meta ? tokensData.meta : void 0;
|
|
1105
|
+
let governance;
|
|
1106
|
+
try {
|
|
1107
|
+
const rulesResponse = await fetch(`${baseUrl}/api/ds/${dsId}/rules`, {
|
|
1108
|
+
method: "GET",
|
|
1109
|
+
headers
|
|
1110
|
+
});
|
|
1111
|
+
if (rulesResponse.ok) {
|
|
1112
|
+
const rulesData = await rulesResponse.json();
|
|
1113
|
+
governance = rulesData;
|
|
1114
|
+
}
|
|
1115
|
+
} catch {
|
|
1116
|
+
console.error("[atomix-mcp] Could not fetch governance rules, continuing without them");
|
|
1117
|
+
}
|
|
1118
|
+
const tokens = "tokens" in tokensData && tokensData.tokens ? tokensData.tokens : tokensData;
|
|
1119
|
+
return {
|
|
1120
|
+
success: true,
|
|
1121
|
+
tokens,
|
|
1122
|
+
governance,
|
|
1123
|
+
meta
|
|
1124
|
+
};
|
|
1125
|
+
} catch (error) {
|
|
1126
|
+
return {
|
|
1127
|
+
success: false,
|
|
1128
|
+
error: `Network error: ${error instanceof Error ? error.message : String(error)}`
|
|
1129
|
+
};
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
function parseCLIArgs(argv = process.argv) {
|
|
1133
|
+
const args = {};
|
|
1134
|
+
for (let i = 0; i < argv.length; i++) {
|
|
1135
|
+
const arg = argv[i];
|
|
1136
|
+
const next = argv[i + 1];
|
|
1137
|
+
switch (arg) {
|
|
1138
|
+
case "--ds-id":
|
|
1139
|
+
if (next && !next.startsWith("--")) {
|
|
1140
|
+
args.dsId = next;
|
|
1141
|
+
i++;
|
|
1142
|
+
}
|
|
1143
|
+
break;
|
|
1144
|
+
case "--api-key":
|
|
1145
|
+
if (next && !next.startsWith("--")) {
|
|
1146
|
+
args.apiKey = next;
|
|
1147
|
+
i++;
|
|
1148
|
+
}
|
|
1149
|
+
break;
|
|
1150
|
+
case "--tenant":
|
|
1151
|
+
if (next && !next.startsWith("--")) {
|
|
1152
|
+
args.tenant = next;
|
|
1153
|
+
args.dsId = args.dsId || next;
|
|
1154
|
+
i++;
|
|
1155
|
+
}
|
|
1156
|
+
break;
|
|
1157
|
+
case "--base-url":
|
|
1158
|
+
if (next && !next.startsWith("--")) {
|
|
1159
|
+
args.baseUrl = next;
|
|
1160
|
+
i++;
|
|
1161
|
+
}
|
|
1162
|
+
break;
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
return args;
|
|
1166
|
+
}
|
|
1167
|
+
function isUserDSMode(args) {
|
|
1168
|
+
return Boolean(args.dsId);
|
|
1169
|
+
}
|
|
1170
|
+
function transformUserTokens(userTokens) {
|
|
1171
|
+
if (userTokens.colors && userTokens.typography && userTokens.spacing) {
|
|
1172
|
+
return userTokens;
|
|
1173
|
+
}
|
|
1174
|
+
if (typeof userTokens.tokens === "object" && userTokens.tokens !== null) {
|
|
1175
|
+
return userTokens.tokens;
|
|
1176
|
+
}
|
|
1177
|
+
return userTokens;
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
// src/ai-rules-generator.ts
|
|
1181
|
+
var AI_TOOLS = {
|
|
1182
|
+
cursor: {
|
|
1183
|
+
id: "cursor",
|
|
1184
|
+
name: "Cursor",
|
|
1185
|
+
rulesFilename: ".cursorrules",
|
|
1186
|
+
rulesPath: ".cursorrules",
|
|
1187
|
+
mcpConfigPath: ".cursor/mcp.json",
|
|
1188
|
+
supportsMarkdown: true,
|
|
1189
|
+
supportsMCP: true,
|
|
1190
|
+
description: "Cursor IDE - AI-first code editor"
|
|
1191
|
+
},
|
|
1192
|
+
copilot: {
|
|
1193
|
+
id: "copilot",
|
|
1194
|
+
name: "GitHub Copilot",
|
|
1195
|
+
rulesFilename: "copilot-instructions.md",
|
|
1196
|
+
rulesPath: ".github/copilot-instructions.md",
|
|
1197
|
+
supportsMarkdown: true,
|
|
1198
|
+
supportsMCP: false,
|
|
1199
|
+
// Uses rules file instead
|
|
1200
|
+
description: "GitHub Copilot in VS Code, JetBrains, etc."
|
|
1201
|
+
},
|
|
1202
|
+
windsurf: {
|
|
1203
|
+
id: "windsurf",
|
|
1204
|
+
name: "Windsurf",
|
|
1205
|
+
rulesFilename: ".windsurfrules",
|
|
1206
|
+
rulesPath: ".windsurfrules",
|
|
1207
|
+
mcpConfigPath: ".windsurf/mcp.json",
|
|
1208
|
+
supportsMarkdown: true,
|
|
1209
|
+
supportsMCP: true,
|
|
1210
|
+
description: "Windsurf Editor by Codeium"
|
|
1211
|
+
},
|
|
1212
|
+
cline: {
|
|
1213
|
+
id: "cline",
|
|
1214
|
+
name: "Cline",
|
|
1215
|
+
rulesFilename: ".clinerules",
|
|
1216
|
+
rulesPath: ".clinerules",
|
|
1217
|
+
supportsMarkdown: true,
|
|
1218
|
+
supportsMCP: true,
|
|
1219
|
+
description: "Cline VS Code extension (formerly Claude Dev)"
|
|
1220
|
+
},
|
|
1221
|
+
continue: {
|
|
1222
|
+
id: "continue",
|
|
1223
|
+
name: "Continue",
|
|
1224
|
+
rulesFilename: ".continuerules",
|
|
1225
|
+
rulesPath: ".continuerules",
|
|
1226
|
+
mcpConfigPath: ".continue/config.json",
|
|
1227
|
+
supportsMarkdown: true,
|
|
1228
|
+
supportsMCP: true,
|
|
1229
|
+
description: "Continue - open source AI code assistant"
|
|
1230
|
+
},
|
|
1231
|
+
zed: {
|
|
1232
|
+
id: "zed",
|
|
1233
|
+
name: "Zed",
|
|
1234
|
+
rulesFilename: ".zed/assistant/rules.md",
|
|
1235
|
+
rulesPath: ".zed/assistant/rules.md",
|
|
1236
|
+
supportsMarkdown: true,
|
|
1237
|
+
supportsMCP: true,
|
|
1238
|
+
description: "Zed Editor with AI assistant"
|
|
1239
|
+
},
|
|
1240
|
+
"claude-desktop": {
|
|
1241
|
+
id: "claude-desktop",
|
|
1242
|
+
name: "Claude Desktop",
|
|
1243
|
+
rulesFilename: "",
|
|
1244
|
+
rulesPath: "",
|
|
1245
|
+
mcpConfigPath: "~/Library/Application Support/Claude/claude_desktop_config.json",
|
|
1246
|
+
supportsMarkdown: false,
|
|
1247
|
+
supportsMCP: true,
|
|
1248
|
+
description: "Claude Desktop App by Anthropic"
|
|
1249
|
+
},
|
|
1250
|
+
generic: {
|
|
1251
|
+
id: "generic",
|
|
1252
|
+
name: "Generic AI",
|
|
1253
|
+
rulesFilename: "AI_GUIDELINES.md",
|
|
1254
|
+
rulesPath: "AI_GUIDELINES.md",
|
|
1255
|
+
supportsMarkdown: true,
|
|
1256
|
+
supportsMCP: false,
|
|
1257
|
+
description: "Generic guidelines for any AI tool"
|
|
1258
|
+
}
|
|
1259
|
+
};
|
|
1260
|
+
function generateMCPConfig(tool, options = {}) {
|
|
1261
|
+
const {
|
|
1262
|
+
serverPath,
|
|
1263
|
+
useNpx = true,
|
|
1264
|
+
dsId,
|
|
1265
|
+
apiKey,
|
|
1266
|
+
tenantId,
|
|
1267
|
+
// Legacy support
|
|
1268
|
+
projectName = "my-project"
|
|
1269
|
+
} = options;
|
|
1270
|
+
const npxCommand = useNpx ? "npx" : "node";
|
|
1271
|
+
const npxArgs = useNpx ? ["@atomixstudio/mcp@latest"] : [serverPath || "./node_modules/@atomixstudio/mcp/dist/index.js"];
|
|
1272
|
+
const effectiveDsId = dsId || tenantId;
|
|
1273
|
+
if (effectiveDsId && effectiveDsId !== "default") {
|
|
1274
|
+
npxArgs.push("--ds-id", effectiveDsId);
|
|
1275
|
+
if (apiKey) {
|
|
1276
|
+
npxArgs.push("--api-key", apiKey);
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
switch (tool) {
|
|
1280
|
+
case "cursor": {
|
|
1281
|
+
const config = {
|
|
1282
|
+
mcpServers: {
|
|
1283
|
+
atomix: {
|
|
1284
|
+
command: npxCommand,
|
|
1285
|
+
args: npxArgs
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
};
|
|
1289
|
+
return {
|
|
1290
|
+
tool: "cursor",
|
|
1291
|
+
filename: "mcp.json",
|
|
1292
|
+
path: ".cursor/mcp.json",
|
|
1293
|
+
content: JSON.stringify(config, null, 2),
|
|
1294
|
+
instructions: `
|
|
1295
|
+
## Cursor MCP Setup
|
|
1296
|
+
|
|
1297
|
+
1. Create the file \`.cursor/mcp.json\` in your project root
|
|
1298
|
+
2. Paste the configuration below
|
|
1299
|
+
3. Restart Cursor IDE
|
|
1300
|
+
4. The Atomix MCP server will be available in Cursor's AI features
|
|
1301
|
+
|
|
1302
|
+
### Configuration File
|
|
1303
|
+
\`\`\`json
|
|
1304
|
+
${JSON.stringify(config, null, 2)}
|
|
1305
|
+
\`\`\`
|
|
1306
|
+
|
|
1307
|
+
### Verify Setup
|
|
1308
|
+
After restarting Cursor, you can verify the MCP server is working by:
|
|
1309
|
+
- Opening the AI chat (Cmd/Ctrl + L)
|
|
1310
|
+
- Asking: "What design tokens are available?"
|
|
1311
|
+
- The AI should query the Atomix MCP server and list token categories
|
|
1312
|
+
`.trim()
|
|
1313
|
+
};
|
|
1314
|
+
}
|
|
1315
|
+
case "claude-desktop": {
|
|
1316
|
+
const config = {
|
|
1317
|
+
mcpServers: {
|
|
1318
|
+
atomix: {
|
|
1319
|
+
command: npxCommand,
|
|
1320
|
+
args: npxArgs
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
};
|
|
1324
|
+
const configPath = process.platform === "darwin" ? "~/Library/Application Support/Claude/claude_desktop_config.json" : process.platform === "win32" ? "%APPDATA%\\Claude\\claude_desktop_config.json" : "~/.config/Claude/claude_desktop_config.json";
|
|
1325
|
+
return {
|
|
1326
|
+
tool: "claude-desktop",
|
|
1327
|
+
filename: "claude_desktop_config.json",
|
|
1328
|
+
path: configPath,
|
|
1329
|
+
content: JSON.stringify(config, null, 2),
|
|
1330
|
+
instructions: `
|
|
1331
|
+
## Claude Desktop MCP Setup
|
|
1332
|
+
|
|
1333
|
+
1. Locate your Claude Desktop config file:
|
|
1334
|
+
- **macOS**: \`${configPath}\`
|
|
1335
|
+
- **Windows**: \`%APPDATA%\\Claude\\claude_desktop_config.json\`
|
|
1336
|
+
- **Linux**: \`~/.config/Claude/claude_desktop_config.json\`
|
|
1337
|
+
|
|
1338
|
+
2. Create or edit the file with the configuration below
|
|
1339
|
+
|
|
1340
|
+
3. Restart Claude Desktop
|
|
1341
|
+
|
|
1342
|
+
4. The Atomix MCP server will be available when chatting with Claude
|
|
1343
|
+
|
|
1344
|
+
### Configuration File
|
|
1345
|
+
\`\`\`json
|
|
1346
|
+
${JSON.stringify(config, null, 2)}
|
|
1347
|
+
\`\`\`
|
|
1348
|
+
|
|
1349
|
+
### Verify Setup
|
|
1350
|
+
After restarting Claude Desktop:
|
|
1351
|
+
- Start a new conversation
|
|
1352
|
+
- Ask: "Can you check what Atomix design tokens are available?"
|
|
1353
|
+
- Claude should use the MCP server to query tokens
|
|
1354
|
+
`.trim()
|
|
1355
|
+
};
|
|
1356
|
+
}
|
|
1357
|
+
case "windsurf": {
|
|
1358
|
+
const config = {
|
|
1359
|
+
mcpServers: {
|
|
1360
|
+
atomix: {
|
|
1361
|
+
command: npxCommand,
|
|
1362
|
+
args: npxArgs
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1365
|
+
};
|
|
1366
|
+
return {
|
|
1367
|
+
tool: "windsurf",
|
|
1368
|
+
filename: "mcp.json",
|
|
1369
|
+
path: ".windsurf/mcp.json",
|
|
1370
|
+
content: JSON.stringify(config, null, 2),
|
|
1371
|
+
instructions: `
|
|
1372
|
+
## Windsurf MCP Setup
|
|
1373
|
+
|
|
1374
|
+
1. Create the file \`.windsurf/mcp.json\` in your project root
|
|
1375
|
+
2. Paste the configuration below
|
|
1376
|
+
3. Restart Windsurf Editor
|
|
1377
|
+
4. The Atomix MCP server will be available in Cascade
|
|
1378
|
+
|
|
1379
|
+
### Configuration File
|
|
1380
|
+
\`\`\`json
|
|
1381
|
+
${JSON.stringify(config, null, 2)}
|
|
1382
|
+
\`\`\`
|
|
1383
|
+
`.trim()
|
|
1384
|
+
};
|
|
1385
|
+
}
|
|
1386
|
+
case "continue": {
|
|
1387
|
+
const config = {
|
|
1388
|
+
models: [],
|
|
1389
|
+
mcpServers: [
|
|
1390
|
+
{
|
|
1391
|
+
name: "atomix",
|
|
1392
|
+
command: npxCommand,
|
|
1393
|
+
args: npxArgs
|
|
1394
|
+
}
|
|
1395
|
+
]
|
|
1396
|
+
};
|
|
1397
|
+
return {
|
|
1398
|
+
tool: "continue",
|
|
1399
|
+
filename: "config.json",
|
|
1400
|
+
path: ".continue/config.json",
|
|
1401
|
+
content: JSON.stringify(config, null, 2),
|
|
1402
|
+
instructions: `
|
|
1403
|
+
## Continue MCP Setup
|
|
1404
|
+
|
|
1405
|
+
1. Create or edit \`.continue/config.json\` in your project root
|
|
1406
|
+
2. Add the mcpServers section below
|
|
1407
|
+
3. Restart VS Code
|
|
1408
|
+
4. The Atomix MCP server will be available in Continue
|
|
1409
|
+
|
|
1410
|
+
### Configuration File
|
|
1411
|
+
\`\`\`json
|
|
1412
|
+
${JSON.stringify(config, null, 2)}
|
|
1413
|
+
\`\`\`
|
|
1414
|
+
|
|
1415
|
+
Note: If you already have a config.json, merge the mcpServers array.
|
|
1416
|
+
`.trim()
|
|
1417
|
+
};
|
|
1418
|
+
}
|
|
1419
|
+
case "vscode": {
|
|
1420
|
+
return {
|
|
1421
|
+
tool: "vscode",
|
|
1422
|
+
filename: "settings.json",
|
|
1423
|
+
path: ".vscode/settings.json",
|
|
1424
|
+
content: JSON.stringify({
|
|
1425
|
+
"mcp.servers": {
|
|
1426
|
+
atomix: {
|
|
1427
|
+
command: npxCommand,
|
|
1428
|
+
args: npxArgs
|
|
1429
|
+
}
|
|
1430
|
+
}
|
|
1431
|
+
}, null, 2),
|
|
1432
|
+
instructions: `
|
|
1433
|
+
## VS Code MCP Setup
|
|
1434
|
+
|
|
1435
|
+
For VS Code, MCP support depends on your AI extension:
|
|
1436
|
+
|
|
1437
|
+
### Option 1: Use GitHub Copilot Instructions
|
|
1438
|
+
Create \`.github/copilot-instructions.md\` with Atomix rules (use getAIToolRules)
|
|
1439
|
+
|
|
1440
|
+
### Option 2: Use Continue Extension
|
|
1441
|
+
See Continue setup instructions above
|
|
1442
|
+
|
|
1443
|
+
### Option 3: Use Cline Extension
|
|
1444
|
+
1. Install Cline extension
|
|
1445
|
+
2. Cline will auto-detect MCP servers in .cursor/mcp.json or .vscode/settings.json
|
|
1446
|
+
|
|
1447
|
+
### Settings.json (for MCP-aware extensions)
|
|
1448
|
+
\`\`\`json
|
|
1449
|
+
{
|
|
1450
|
+
"mcp.servers": {
|
|
1451
|
+
"atomix": {
|
|
1452
|
+
"command": "${npxCommand}",
|
|
1453
|
+
"args": ${JSON.stringify(npxArgs)}
|
|
1454
|
+
}
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
\`\`\`
|
|
1458
|
+
`.trim()
|
|
1459
|
+
};
|
|
1460
|
+
}
|
|
1461
|
+
default:
|
|
1462
|
+
throw new Error(`Unknown MCP config tool: ${tool}`);
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
function generateAllMCPConfigs(options = {}) {
|
|
1466
|
+
const tools = ["cursor", "claude-desktop", "windsurf", "continue", "vscode"];
|
|
1467
|
+
return tools.map((tool) => generateMCPConfig(tool, options));
|
|
1468
|
+
}
|
|
1469
|
+
function getSetupInstructions(toolId) {
|
|
1470
|
+
const tool = AI_TOOLS[toolId];
|
|
1471
|
+
if (!tool) {
|
|
1472
|
+
throw new Error(`Unknown AI tool: ${toolId}. Available: ${Object.keys(AI_TOOLS).join(", ")}`);
|
|
1473
|
+
}
|
|
1474
|
+
const baseInstructions = `
|
|
1475
|
+
# ${tool.name} Setup for Atomix Design System
|
|
1476
|
+
|
|
1477
|
+
${tool.description}
|
|
1478
|
+
|
|
1479
|
+
## Overview
|
|
1480
|
+
|
|
1481
|
+
${tool.supportsMCP ? `${tool.name} supports MCP (Model Context Protocol), allowing direct integration with the Atomix design token server.` : `${tool.name} uses a rules file to understand the Atomix design system.`}
|
|
1482
|
+
|
|
1483
|
+
`;
|
|
1484
|
+
switch (toolId) {
|
|
1485
|
+
case "cursor":
|
|
1486
|
+
return baseInstructions + `
|
|
1487
|
+
## Quick Setup
|
|
1488
|
+
|
|
1489
|
+
### Step 1: Add MCP Configuration
|
|
1490
|
+
|
|
1491
|
+
Create \`.cursor/mcp.json\` in your project root:
|
|
1492
|
+
|
|
1493
|
+
\`\`\`json
|
|
1494
|
+
{
|
|
1495
|
+
"mcpServers": {
|
|
1496
|
+
"atomix": {
|
|
1497
|
+
"command": "npx",
|
|
1498
|
+
"args": ["@atomixstudio/mcp@latest"]
|
|
1499
|
+
}
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
1502
|
+
\`\`\`
|
|
1503
|
+
|
|
1504
|
+
### Step 2: Add Rules File (Optional but Recommended)
|
|
1505
|
+
|
|
1506
|
+
Create \`.cursorrules\` in your project root with Atomix guidelines.
|
|
1507
|
+
Use \`getAIToolRules({ tool: "cursor" })\` to generate this file.
|
|
1508
|
+
|
|
1509
|
+
### Step 3: Restart Cursor
|
|
1510
|
+
|
|
1511
|
+
After adding the MCP config, restart Cursor IDE completely.
|
|
1512
|
+
|
|
1513
|
+
## Verification
|
|
1514
|
+
|
|
1515
|
+
1. Open AI chat (Cmd/Ctrl + L)
|
|
1516
|
+
2. Ask: "What Atomix design tokens are available?"
|
|
1517
|
+
3. Cursor should query the MCP server and respond with token information
|
|
1518
|
+
|
|
1519
|
+
## Available MCP Tools
|
|
1520
|
+
|
|
1521
|
+
Once configured, you can use these in conversations:
|
|
1522
|
+
- \`getToken("colors.static.brand.primary")\` - Get a specific token
|
|
1523
|
+
- \`listTokens("colors")\` - List tokens in a category
|
|
1524
|
+
- \`getComponentTokens("button")\` - Get component tokens
|
|
1525
|
+
- \`validateUsage("#ff0000")\` - Check if a value is allowed
|
|
1526
|
+
- \`searchTokens("brand")\` - Search for tokens
|
|
1527
|
+
`;
|
|
1528
|
+
case "claude-desktop":
|
|
1529
|
+
return baseInstructions + `
|
|
1530
|
+
## Quick Setup
|
|
1531
|
+
|
|
1532
|
+
### Step 1: Locate Config File
|
|
1533
|
+
|
|
1534
|
+
- **macOS**: \`~/Library/Application Support/Claude/claude_desktop_config.json\`
|
|
1535
|
+
- **Windows**: \`%APPDATA%\\Claude\\claude_desktop_config.json\`
|
|
1536
|
+
- **Linux**: \`~/.config/Claude/claude_desktop_config.json\`
|
|
1537
|
+
|
|
1538
|
+
### Step 2: Add MCP Configuration
|
|
1539
|
+
|
|
1540
|
+
Create or edit the config file:
|
|
1541
|
+
|
|
1542
|
+
\`\`\`json
|
|
1543
|
+
{
|
|
1544
|
+
"mcpServers": {
|
|
1545
|
+
"atomix": {
|
|
1546
|
+
"command": "npx",
|
|
1547
|
+
"args": ["@atomixstudio/mcp@latest"]
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
1551
|
+
\`\`\`
|
|
1552
|
+
|
|
1553
|
+
### Step 3: Restart Claude Desktop
|
|
1554
|
+
|
|
1555
|
+
Completely quit and reopen Claude Desktop.
|
|
1556
|
+
|
|
1557
|
+
## Verification
|
|
1558
|
+
|
|
1559
|
+
Start a new conversation and ask:
|
|
1560
|
+
"Can you check what Atomix design tokens are available?"
|
|
1561
|
+
|
|
1562
|
+
Claude should use the MCP server to query and list tokens.
|
|
1563
|
+
`;
|
|
1564
|
+
case "copilot":
|
|
1565
|
+
return baseInstructions + `
|
|
1566
|
+
## Quick Setup
|
|
1567
|
+
|
|
1568
|
+
GitHub Copilot doesn't support MCP directly, but uses instruction files.
|
|
1569
|
+
|
|
1570
|
+
### Step 1: Create Instructions File
|
|
1571
|
+
|
|
1572
|
+
Create \`.github/copilot-instructions.md\` in your project:
|
|
1573
|
+
|
|
1574
|
+
Use \`getAIToolRules({ tool: "copilot" })\` to generate the content.
|
|
1575
|
+
|
|
1576
|
+
### Step 2: Enable Custom Instructions
|
|
1577
|
+
|
|
1578
|
+
In VS Code settings, ensure:
|
|
1579
|
+
\`\`\`json
|
|
1580
|
+
{
|
|
1581
|
+
"github.copilot.chat.codeGeneration.useInstructionFiles": true
|
|
1582
|
+
}
|
|
1583
|
+
\`\`\`
|
|
1584
|
+
|
|
1585
|
+
## Verification
|
|
1586
|
+
|
|
1587
|
+
1. Open Copilot Chat
|
|
1588
|
+
2. Ask about design tokens
|
|
1589
|
+
3. Copilot should follow the Atomix guidelines from the instructions file
|
|
1590
|
+
`;
|
|
1591
|
+
case "windsurf":
|
|
1592
|
+
return baseInstructions + `
|
|
1593
|
+
## Quick Setup
|
|
1594
|
+
|
|
1595
|
+
### Step 1: Add MCP Configuration
|
|
1596
|
+
|
|
1597
|
+
Create \`.windsurf/mcp.json\` in your project root:
|
|
1598
|
+
|
|
1599
|
+
\`\`\`json
|
|
1600
|
+
{
|
|
1601
|
+
"mcpServers": {
|
|
1602
|
+
"atomix": {
|
|
1603
|
+
"command": "npx",
|
|
1604
|
+
"args": ["@atomixstudio/mcp@latest"]
|
|
1605
|
+
}
|
|
1606
|
+
}
|
|
1607
|
+
}
|
|
1608
|
+
\`\`\`
|
|
1609
|
+
|
|
1610
|
+
### Step 2: Add Rules File
|
|
1611
|
+
|
|
1612
|
+
Create \`.windsurfrules\` in your project root.
|
|
1613
|
+
Use \`getAIToolRules({ tool: "windsurf" })\` to generate this file.
|
|
1614
|
+
|
|
1615
|
+
### Step 3: Restart Windsurf
|
|
1616
|
+
|
|
1617
|
+
Restart the editor to load the MCP configuration.
|
|
1618
|
+
`;
|
|
1619
|
+
case "cline":
|
|
1620
|
+
return baseInstructions + `
|
|
1621
|
+
## Quick Setup
|
|
1622
|
+
|
|
1623
|
+
### Step 1: Create Rules File
|
|
1624
|
+
|
|
1625
|
+
Create \`.clinerules\` in your project root.
|
|
1626
|
+
Use \`getAIToolRules({ tool: "cline" })\` to generate this file.
|
|
1627
|
+
|
|
1628
|
+
### Step 2: MCP Auto-Detection
|
|
1629
|
+
|
|
1630
|
+
Cline can auto-detect MCP servers from:
|
|
1631
|
+
- \`.cursor/mcp.json\`
|
|
1632
|
+
- Project configuration
|
|
1633
|
+
|
|
1634
|
+
If you have Cursor's MCP config, Cline will use it automatically.
|
|
1635
|
+
|
|
1636
|
+
### Step 3: Manual MCP Setup (if needed)
|
|
1637
|
+
|
|
1638
|
+
In Cline settings, add MCP server configuration:
|
|
1639
|
+
- Command: \`npx\`
|
|
1640
|
+
- Args: \`@atomixstudio/mcp@latest\`
|
|
1641
|
+
`;
|
|
1642
|
+
case "continue":
|
|
1643
|
+
return baseInstructions + `
|
|
1644
|
+
## Quick Setup
|
|
1645
|
+
|
|
1646
|
+
### Step 1: Add MCP Configuration
|
|
1647
|
+
|
|
1648
|
+
Create or edit \`.continue/config.json\`:
|
|
1649
|
+
|
|
1650
|
+
\`\`\`json
|
|
1651
|
+
{
|
|
1652
|
+
"mcpServers": [
|
|
1653
|
+
{
|
|
1654
|
+
"name": "atomix",
|
|
1655
|
+
"command": "npx",
|
|
1656
|
+
"args": ["@atomixstudio/mcp@latest"]
|
|
1657
|
+
}
|
|
1658
|
+
]
|
|
1659
|
+
}
|
|
1660
|
+
\`\`\`
|
|
1661
|
+
|
|
1662
|
+
### Step 2: Add Rules File (Optional)
|
|
1663
|
+
|
|
1664
|
+
Create \`.continuerules\` in your project root.
|
|
1665
|
+
Use \`getAIToolRules({ tool: "continue" })\` to generate this file.
|
|
1666
|
+
|
|
1667
|
+
### Step 3: Restart VS Code
|
|
1668
|
+
|
|
1669
|
+
Restart VS Code to load the Continue configuration.
|
|
1670
|
+
`;
|
|
1671
|
+
case "zed":
|
|
1672
|
+
return baseInstructions + `
|
|
1673
|
+
## Quick Setup
|
|
1674
|
+
|
|
1675
|
+
### Step 1: Add Rules File
|
|
1676
|
+
|
|
1677
|
+
Create \`.zed/assistant/rules.md\` in your project root.
|
|
1678
|
+
Use \`getAIToolRules({ tool: "zed" })\` to generate this file.
|
|
1679
|
+
|
|
1680
|
+
### Step 2: MCP Configuration
|
|
1681
|
+
|
|
1682
|
+
Zed's MCP support is configured in Zed settings.
|
|
1683
|
+
Check Zed documentation for the latest MCP configuration format.
|
|
1684
|
+
`;
|
|
1685
|
+
default:
|
|
1686
|
+
return baseInstructions + `
|
|
1687
|
+
## Generic Setup
|
|
1688
|
+
|
|
1689
|
+
### Step 1: Create Guidelines File
|
|
1690
|
+
|
|
1691
|
+
Create \`AI_GUIDELINES.md\` in your project root.
|
|
1692
|
+
Use \`getAIToolRules({ tool: "generic" })\` to generate this file.
|
|
1693
|
+
|
|
1694
|
+
### Step 2: Reference in Prompts
|
|
1695
|
+
|
|
1696
|
+
When working with AI tools, reference the guidelines file in your prompts
|
|
1697
|
+
or include it in your context.
|
|
1698
|
+
`;
|
|
1699
|
+
}
|
|
1700
|
+
}
|
|
1701
|
+
function generateCursorRules(projectName, strict) {
|
|
1702
|
+
const componentList = Object.keys(COMPONENT_TOKENS).join(", ");
|
|
1703
|
+
const categoryList = TOKEN_CATEGORIES.join(", ");
|
|
1704
|
+
const strictRules = strict ? `
|
|
1705
|
+
## Hard Rules (Strict Mode)
|
|
1706
|
+
|
|
1707
|
+
1. **NO arbitrary values** \u2014 \`w-[350px]\`, \`bg-[#ff0000]\` are FORBIDDEN
|
|
1708
|
+
2. **NO hardcoded colors** \u2014 All colors must use CSS variables or token imports
|
|
1709
|
+
3. **NO hardcoded spacing** \u2014 Use \`spacing.*\` tokens (e.g., \`@spacing.md\`, \`@spacing.lg\`)
|
|
1710
|
+
4. **NO hardcoded typography** \u2014 Use \`typography.fontSize.*\` and \`typography.fontWeight.*\`
|
|
1711
|
+
5. **Token vocabulary only** \u2014 If a value isn't in the design system, don't use it
|
|
1712
|
+
|
|
1713
|
+
### Escape Hatch
|
|
1714
|
+
|
|
1715
|
+
If external constraints require arbitrary values:
|
|
1716
|
+
|
|
1717
|
+
\`\`\`tsx
|
|
1718
|
+
{/* @design-override: YouTube embed requires 16:9 aspect ratio */}
|
|
1719
|
+
<div className="aspect-[16/9]">
|
|
1720
|
+
\`\`\`
|
|
1721
|
+
|
|
1722
|
+
Document the reason. The override comment signals intentional deviation.
|
|
1723
|
+
` : `
|
|
1724
|
+
## Guidelines (Non-Strict Mode)
|
|
1725
|
+
|
|
1726
|
+
1. **Prefer tokens** \u2014 Use design system tokens when available
|
|
1727
|
+
2. **Document overrides** \u2014 If using arbitrary values, add a comment explaining why
|
|
1728
|
+
3. **Consistency** \u2014 Match existing patterns in the codebase
|
|
1729
|
+
`;
|
|
1730
|
+
const tierGuidance = `
|
|
1731
|
+
## Token Tier System (Critical)
|
|
1732
|
+
|
|
1733
|
+
Atomix tokens are organized in tiers. Understanding this hierarchy is essential:
|
|
1734
|
+
|
|
1735
|
+
### Tier 1: Primitives (Read-Only Reference)
|
|
1736
|
+
|
|
1737
|
+
Raw foundational values. **DO NOT use these directly in components.**
|
|
1738
|
+
|
|
1739
|
+
| Type | Example Path | Example Value | Use For |
|
|
1740
|
+
|------|-------------|---------------|---------|
|
|
1741
|
+
| Color scales | \`colors.scales.green.500\` | \`#10B981\` | Reference only |
|
|
1742
|
+
| Spacing scale | \`spacing.md\` | \`1rem\` | Token reference |
|
|
1743
|
+
| Font sizes | \`typography.fontSize.sm\` | \`0.875rem\` | Reference only |
|
|
1744
|
+
| Radius scale | \`radius.lg\` | \`12px\` | Token reference |
|
|
1745
|
+
|
|
1746
|
+
These values are **locked** \u2014 AI tools should never suggest modifying them.
|
|
1747
|
+
|
|
1748
|
+
### Tier 2: Semantics (Primary API)
|
|
1749
|
+
|
|
1750
|
+
Purpose-driven tokens that reference primitives. **USE THESE in components.**
|
|
1751
|
+
|
|
1752
|
+
| Type | Example Path | Maps To | Use For |
|
|
1753
|
+
|------|-------------|---------|---------|
|
|
1754
|
+
| Mode colors | \`colors.modes.light.bgSurface\` | \`neutral[5]\` | Backgrounds |
|
|
1755
|
+
| Semantic radius | \`radius.semantic.button\` | \`scale.md\` | Component corners |
|
|
1756
|
+
| TypeSets | \`typography.typeSets.title-lg\` | Composed style | Text styling |
|
|
1757
|
+
| Focus rings | \`shadows.focus.ring\` | Composed shadow | A11y focus |
|
|
1758
|
+
|
|
1759
|
+
These are **editable via Atomix Designer** and auto-switch for dark mode.
|
|
1760
|
+
|
|
1761
|
+
### Tier 3: Component Tokens
|
|
1762
|
+
|
|
1763
|
+
Component-specific token assignments. Managed via Atomix Designer.
|
|
1764
|
+
|
|
1765
|
+
- Button variants: primary, secondary, outline, ghost
|
|
1766
|
+
- Card variants: default, outlined, elevated
|
|
1767
|
+
- Sizes: sm, md, lg
|
|
1768
|
+
|
|
1769
|
+
---
|
|
1770
|
+
|
|
1771
|
+
### Correct Token Usage
|
|
1772
|
+
|
|
1773
|
+
\`\`\`tsx
|
|
1774
|
+
// \u2705 CORRECT: Use semantic color (Tier 2)
|
|
1775
|
+
style={{ backgroundColor: "var(--atomix-bg-surface)" }}
|
|
1776
|
+
|
|
1777
|
+
// \u274C WRONG: Using primitive directly (Tier 1)
|
|
1778
|
+
style={{ backgroundColor: colors.scales.neutral[5] }}
|
|
1779
|
+
|
|
1780
|
+
// \u2705 CORRECT: Use typeSet (Tier 2)
|
|
1781
|
+
style={{ ...typography.typeSets["title-lg"] }}
|
|
1782
|
+
|
|
1783
|
+
// \u274C WRONG: Using primitive font size (Tier 1)
|
|
1784
|
+
style={{ fontSize: typography.fontSize["2xl"] }}
|
|
1785
|
+
\`\`\`
|
|
1786
|
+
|
|
1787
|
+
### When to Reference Primitives
|
|
1788
|
+
|
|
1789
|
+
Primitives are useful for:
|
|
1790
|
+
1. **Validation** \u2014 Checking if a hardcoded value matches a token
|
|
1791
|
+
2. **Documentation** \u2014 Explaining what a semantic token resolves to
|
|
1792
|
+
3. **A11y calculations** \u2014 Contrast ratio checks need actual hex values
|
|
1793
|
+
4. **Debug logging** \u2014 Showing resolved values in dev tools
|
|
1794
|
+
|
|
1795
|
+
But **NEVER** use primitive paths directly in component styling code.
|
|
1796
|
+
`;
|
|
1797
|
+
return `# ${projectName} \u2014 Atomix Design System Rules
|
|
1798
|
+
|
|
1799
|
+
This project uses the **Atomix Design System**. All UI code must follow these guidelines.
|
|
1800
|
+
|
|
1801
|
+
---
|
|
1802
|
+
${strictRules}
|
|
1803
|
+
---
|
|
1804
|
+
${tierGuidance}
|
|
1805
|
+
---
|
|
1806
|
+
|
|
1807
|
+
## Token Categories
|
|
1808
|
+
|
|
1809
|
+
Available token categories: ${categoryList}
|
|
1810
|
+
|
|
1811
|
+
### Color Tokens
|
|
1812
|
+
|
|
1813
|
+
Use CSS variables for all colors:
|
|
1814
|
+
|
|
1815
|
+
\`\`\`tsx
|
|
1816
|
+
// \u2705 Correct
|
|
1817
|
+
style={{ backgroundColor: "var(--atomix-bg-surface)" }}
|
|
1818
|
+
style={{ color: "var(--atomix-text-primary)" }}
|
|
1819
|
+
|
|
1820
|
+
// \u274C Wrong
|
|
1821
|
+
style={{ backgroundColor: "#ffffff" }}
|
|
1822
|
+
style={{ color: "rgb(0, 0, 0)" }}
|
|
1823
|
+
\`\`\`
|
|
1824
|
+
|
|
1825
|
+
**Semantic color aliases:**
|
|
1826
|
+
- \`--atomix-brand\` \u2014 Primary brand color
|
|
1827
|
+
- \`--atomix-bg-page\` \u2014 Page background
|
|
1828
|
+
- \`--atomix-bg-surface\` \u2014 Card/surface background
|
|
1829
|
+
- \`--atomix-bg-muted\` \u2014 Muted/secondary background
|
|
1830
|
+
- \`--atomix-text-primary\` \u2014 Primary text color
|
|
1831
|
+
- \`--atomix-text-secondary\` \u2014 Secondary text color
|
|
1832
|
+
- \`--atomix-text-muted\` \u2014 Muted/placeholder text
|
|
1833
|
+
- \`--atomix-icon-brand\` \u2014 Brand-colored icons
|
|
1834
|
+
- \`--atomix-icon-strong\` \u2014 High contrast icons
|
|
1835
|
+
- \`--atomix-icon-subtle\` \u2014 Medium contrast icons
|
|
1836
|
+
- \`--atomix-icon-disabled\` \u2014 Disabled state icons
|
|
1837
|
+
- \`--atomix-border-primary\` \u2014 Default border color
|
|
1838
|
+
|
|
1839
|
+
### Spacing Tokens
|
|
1840
|
+
|
|
1841
|
+
Use spacing tokens for all padding, margin, and gap values:
|
|
1842
|
+
|
|
1843
|
+
\`\`\`tsx
|
|
1844
|
+
import { spacing } from "@atomix/tokens/primitives";
|
|
1845
|
+
|
|
1846
|
+
// \u2705 Correct
|
|
1847
|
+
style={{ padding: spacing.inset.md }}
|
|
1848
|
+
style={{ gap: spacing.gap.sm }}
|
|
1849
|
+
|
|
1850
|
+
// \u274C Wrong
|
|
1851
|
+
style={{ padding: "16px" }}
|
|
1852
|
+
style={{ gap: "8px" }}
|
|
1853
|
+
\`\`\`
|
|
1854
|
+
|
|
1855
|
+
**Spacing scale:** xs, sm, md, lg, xl, 2xl, 3xl
|
|
1856
|
+
|
|
1857
|
+
### Typography Tokens
|
|
1858
|
+
|
|
1859
|
+
Use typography tokens for font properties:
|
|
1860
|
+
|
|
1861
|
+
\`\`\`tsx
|
|
1862
|
+
import { typography } from "@atomix/tokens/primitives";
|
|
1863
|
+
|
|
1864
|
+
// \u2705 Correct
|
|
1865
|
+
style={{
|
|
1866
|
+
fontSize: typography.fontSize.sm,
|
|
1867
|
+
fontWeight: typography.fontWeight.medium,
|
|
1868
|
+
lineHeight: typography.lineHeight.normal,
|
|
1869
|
+
}}
|
|
1870
|
+
|
|
1871
|
+
// \u274C Wrong
|
|
1872
|
+
style={{ fontSize: "14px", fontWeight: 500 }}
|
|
1873
|
+
\`\`\`
|
|
1874
|
+
|
|
1875
|
+
### Motion Tokens
|
|
1876
|
+
|
|
1877
|
+
Use motion tokens for animations:
|
|
1878
|
+
|
|
1879
|
+
\`\`\`tsx
|
|
1880
|
+
import { motion } from "@atomix/tokens/primitives";
|
|
1881
|
+
|
|
1882
|
+
// \u2705 Correct
|
|
1883
|
+
style={{
|
|
1884
|
+
transitionDuration: motion.duration.fast,
|
|
1885
|
+
transitionTimingFunction: motion.easing.ease,
|
|
1886
|
+
}}
|
|
1887
|
+
|
|
1888
|
+
// \u274C Wrong
|
|
1889
|
+
style={{ transition: "all 150ms ease" }}
|
|
1890
|
+
\`\`\`
|
|
1891
|
+
|
|
1892
|
+
---
|
|
1893
|
+
|
|
1894
|
+
## Component Usage
|
|
1895
|
+
|
|
1896
|
+
Available components: ${componentList}
|
|
1897
|
+
|
|
1898
|
+
### Using the MCP Server
|
|
1899
|
+
|
|
1900
|
+
This project has an MCP server for querying design tokens. Use these tools:
|
|
1901
|
+
|
|
1902
|
+
- \`getToken("path.to.token")\` \u2014 Get a specific token value
|
|
1903
|
+
- \`listTokens("colors")\` \u2014 List all tokens in a category
|
|
1904
|
+
- \`getComponentTokens("button")\` \u2014 Get tokens for a component
|
|
1905
|
+
- \`validateUsage("value")\` \u2014 Check if a value follows the design system
|
|
1906
|
+
- \`searchTokens("brand")\` \u2014 Search for tokens by name or value
|
|
1907
|
+
|
|
1908
|
+
### Component Patterns
|
|
1909
|
+
|
|
1910
|
+
When implementing components:
|
|
1911
|
+
|
|
1912
|
+
1. Check the component tokens first: \`getComponentTokens("componentName")\`
|
|
1913
|
+
2. Use the documented variants and sizes
|
|
1914
|
+
3. Apply tokens through CSS variables or direct imports
|
|
1915
|
+
4. Follow the existing component architecture
|
|
1916
|
+
|
|
1917
|
+
---
|
|
1918
|
+
|
|
1919
|
+
## Import Patterns
|
|
1920
|
+
|
|
1921
|
+
\`\`\`tsx
|
|
1922
|
+
// Import primitives for direct use
|
|
1923
|
+
import { colors, spacing, typography, motion } from "@atomix/tokens/primitives";
|
|
1924
|
+
|
|
1925
|
+
// Or import the combined object
|
|
1926
|
+
import { primitives } from "@atomix/tokens";
|
|
1927
|
+
|
|
1928
|
+
// Use CSS variables in styles (preferred for colors)
|
|
1929
|
+
const style = {
|
|
1930
|
+
backgroundColor: "var(--atomix-bg-surface)",
|
|
1931
|
+
padding: spacing.inset.md,
|
|
1932
|
+
borderRadius: "var(--atomix-radius-scale-md)",
|
|
1933
|
+
};
|
|
1934
|
+
\`\`\`
|
|
1935
|
+
|
|
1936
|
+
---
|
|
1937
|
+
|
|
1938
|
+
## Dark Mode
|
|
1939
|
+
|
|
1940
|
+
Colors automatically switch in dark mode when using CSS variables:
|
|
1941
|
+
|
|
1942
|
+
\`\`\`tsx
|
|
1943
|
+
// This works in both light and dark mode
|
|
1944
|
+
style={{
|
|
1945
|
+
backgroundColor: "var(--atomix-bg-surface)",
|
|
1946
|
+
color: "var(--atomix-text-primary)",
|
|
1947
|
+
}}
|
|
1948
|
+
\`\`\`
|
|
1949
|
+
|
|
1950
|
+
The \`.dark\` class on the root element toggles all color variables.
|
|
1951
|
+
|
|
1952
|
+
---
|
|
1953
|
+
|
|
1954
|
+
## When Unsure
|
|
1955
|
+
|
|
1956
|
+
1. **Search tokens first:** Use \`searchTokens("query")\` to find relevant tokens
|
|
1957
|
+
2. **Check component tokens:** Use \`getComponentTokens("component")\` for component-specific values
|
|
1958
|
+
3. **Use the nearest token:** If exact match unavailable, use the closest semantic token
|
|
1959
|
+
4. **Flag for review:** Add \`{/* TODO: need new token? */}\` comment if a token seems missing
|
|
1960
|
+
|
|
1961
|
+
---
|
|
1962
|
+
|
|
1963
|
+
## Reference
|
|
1964
|
+
|
|
1965
|
+
- Token package: \`@atomix/tokens\`
|
|
1966
|
+
- CSS variables: All prefixed with \`--atomix-\`
|
|
1967
|
+
- MCP server: \`atomix-mcp\` (run \`npm run start\` in packages/atomix-mcp)
|
|
1968
|
+
`;
|
|
1969
|
+
}
|
|
1970
|
+
function generateRulesForTool(toolId, projectName, strict) {
|
|
1971
|
+
const tool = AI_TOOLS[toolId];
|
|
1972
|
+
if (!tool) {
|
|
1973
|
+
throw new Error(`Unknown AI tool: ${toolId}. Available: ${Object.keys(AI_TOOLS).join(", ")}`);
|
|
1974
|
+
}
|
|
1975
|
+
const header = `<!-- Generated for ${tool.name} by Atomix MCP Server -->
|
|
1976
|
+
<!-- Tool: ${tool.description} -->
|
|
1977
|
+
<!-- Rules file: ${tool.rulesPath} -->
|
|
1978
|
+
<!-- Generated: ${(/* @__PURE__ */ new Date()).toISOString()} -->
|
|
1979
|
+
|
|
1980
|
+
`;
|
|
1981
|
+
const content = header + generateCursorRules(projectName, strict);
|
|
1982
|
+
return {
|
|
1983
|
+
tool,
|
|
1984
|
+
filename: tool.rulesFilename,
|
|
1985
|
+
path: tool.rulesPath,
|
|
1986
|
+
content
|
|
1987
|
+
};
|
|
1988
|
+
}
|
|
1989
|
+
function generateRulesForAllTools(projectName, strict) {
|
|
1990
|
+
return Object.keys(AI_TOOLS).filter((id) => AI_TOOLS[id].rulesPath !== "").map(
|
|
1991
|
+
(toolId) => generateRulesForTool(toolId, projectName, strict)
|
|
1992
|
+
);
|
|
1993
|
+
}
|
|
1994
|
+
function getSupportedAITools() {
|
|
1995
|
+
return Object.values(AI_TOOLS);
|
|
1996
|
+
}
|
|
1997
|
+
function generateToolSetupGuide(projectName) {
|
|
1998
|
+
const tools = getSupportedAITools();
|
|
1999
|
+
const mcpTools = tools.filter((t) => t.supportsMCP);
|
|
2000
|
+
const rulesTools = tools.filter((t) => t.rulesPath);
|
|
2001
|
+
return `# AI Tool Setup Guide for ${projectName}
|
|
2002
|
+
|
|
2003
|
+
This project uses the **Atomix Design System** with MCP (Model Context Protocol).
|
|
2004
|
+
|
|
2005
|
+
## Quick Start
|
|
2006
|
+
|
|
2007
|
+
Choose your AI tool and follow the setup:
|
|
2008
|
+
|
|
2009
|
+
| Tool | MCP Support | Rules File | Setup Command |
|
|
2010
|
+
|------|-------------|------------|---------------|
|
|
2011
|
+
${tools.map((t) => `| ${t.name} | ${t.supportsMCP ? "Yes" : "No"} | ${t.rulesPath || "N/A"} | \`getSetupInstructions("${t.id}")\` |`).join("\n")}
|
|
2012
|
+
|
|
2013
|
+
## MCP-Enabled Tools (Recommended)
|
|
2014
|
+
|
|
2015
|
+
These tools can query Atomix tokens directly:
|
|
2016
|
+
|
|
2017
|
+
${mcpTools.map((t) => `- **${t.name}** \u2014 ${t.description}`).join("\n")}
|
|
2018
|
+
|
|
2019
|
+
### Generate MCP Config
|
|
2020
|
+
|
|
2021
|
+
\`\`\`
|
|
2022
|
+
exportMCPConfig({ tool: "cursor" }) // For Cursor
|
|
2023
|
+
exportMCPConfig({ tool: "claude-desktop" }) // For Claude Desktop
|
|
2024
|
+
exportMCPConfig({ tool: "all" }) // All configs at once
|
|
2025
|
+
\`\`\`
|
|
2026
|
+
|
|
2027
|
+
## Rules-Based Tools
|
|
2028
|
+
|
|
2029
|
+
These tools use instruction files:
|
|
2030
|
+
|
|
2031
|
+
${rulesTools.filter((t) => !t.supportsMCP).map((t) => `- **${t.name}** \u2014 \`${t.rulesPath}\``).join("\n")}
|
|
2032
|
+
|
|
2033
|
+
### Generate Rules Files
|
|
2034
|
+
|
|
2035
|
+
\`\`\`
|
|
2036
|
+
getAIToolRules({ tool: "copilot" }) // For GitHub Copilot
|
|
2037
|
+
getAIToolRules({ tool: "all" }) // All rules at once
|
|
2038
|
+
\`\`\`
|
|
2039
|
+
|
|
2040
|
+
## Available MCP Tools
|
|
2041
|
+
|
|
2042
|
+
Once connected, AI tools can use:
|
|
2043
|
+
|
|
2044
|
+
| Tool | Description |
|
|
2045
|
+
|------|-------------|
|
|
2046
|
+
| \`getToken\` | Get a specific token by path |
|
|
2047
|
+
| \`listTokens\` | List tokens in a category |
|
|
2048
|
+
| \`getComponentTokens\` | Get tokens for a component |
|
|
2049
|
+
| \`validateUsage\` | Check if a value follows the design system |
|
|
2050
|
+
| \`searchTokens\` | Search tokens by name or value |
|
|
2051
|
+
| \`exportMCPConfig\` | Generate MCP configuration files |
|
|
2052
|
+
| \`getSetupInstructions\` | Get detailed setup instructions |
|
|
2053
|
+
|
|
2054
|
+
## Token Tier System
|
|
2055
|
+
|
|
2056
|
+
| Tier | Mutable | Use For |
|
|
2057
|
+
|------|---------|---------|
|
|
2058
|
+
| Primitive | No | Reference only (validation, a11y) |
|
|
2059
|
+
| Semantic | Yes (Designer) | Primary API for styling |
|
|
2060
|
+
| Component | Yes (Designer) | Component-specific tokens |
|
|
2061
|
+
|
|
2062
|
+
**Rule**: Always use semantic tokens in code. Never use primitive paths directly.
|
|
2063
|
+
`;
|
|
2064
|
+
}
|
|
2065
|
+
|
|
2066
|
+
// src/index.ts
|
|
2067
|
+
function formatTimeAgo(timestamp) {
|
|
2068
|
+
const now = Date.now();
|
|
2069
|
+
const diffMs = now - timestamp;
|
|
2070
|
+
const diffSec = Math.floor(diffMs / 1e3);
|
|
2071
|
+
const diffMin = Math.floor(diffSec / 60);
|
|
2072
|
+
const diffHour = Math.floor(diffMin / 60);
|
|
2073
|
+
const diffDay = Math.floor(diffHour / 24);
|
|
2074
|
+
if (diffSec < 60) return "just now";
|
|
2075
|
+
if (diffMin < 60) return `${diffMin} minute${diffMin > 1 ? "s" : ""} ago`;
|
|
2076
|
+
if (diffHour < 24) return `${diffHour} hour${diffHour > 1 ? "s" : ""} ago`;
|
|
2077
|
+
if (diffDay < 7) return `${diffDay} day${diffDay > 1 ? "s" : ""} ago`;
|
|
2078
|
+
const date = new Date(timestamp);
|
|
2079
|
+
return date.toLocaleDateString("en-US", {
|
|
2080
|
+
month: "short",
|
|
2081
|
+
day: "numeric",
|
|
2082
|
+
year: date.getFullYear() !== (/* @__PURE__ */ new Date()).getFullYear() ? "numeric" : void 0
|
|
2083
|
+
});
|
|
2084
|
+
}
|
|
2085
|
+
var server = new Server(
|
|
2086
|
+
{
|
|
2087
|
+
name: "atomix-mcp",
|
|
2088
|
+
version: "0.1.0"
|
|
2089
|
+
},
|
|
2090
|
+
{
|
|
2091
|
+
capabilities: {
|
|
2092
|
+
tools: {},
|
|
2093
|
+
resources: {}
|
|
2094
|
+
}
|
|
2095
|
+
}
|
|
2096
|
+
);
|
|
2097
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
2098
|
+
return {
|
|
2099
|
+
tools: [
|
|
2100
|
+
{
|
|
2101
|
+
name: "getToken",
|
|
2102
|
+
description: "Get a specific design token by its path. Returns value, CSS variable, and tier metadata. IMPORTANT: Tokens are tiered - 'primitive' tokens are read-only reference values, 'semantic' tokens are the primary API for styling.",
|
|
2103
|
+
inputSchema: {
|
|
2104
|
+
type: "object",
|
|
2105
|
+
properties: {
|
|
2106
|
+
path: {
|
|
2107
|
+
type: "string",
|
|
2108
|
+
description: "Token path in dot notation. Prefer semantic paths (colors.modes.light.bgPage) over primitive paths (colors.scales.green.500)"
|
|
2109
|
+
},
|
|
2110
|
+
tenantId: {
|
|
2111
|
+
type: "string",
|
|
2112
|
+
description: "Tenant ID for multi-tenant support (optional, defaults to 'default')"
|
|
2113
|
+
}
|
|
2114
|
+
},
|
|
2115
|
+
required: ["path"]
|
|
2116
|
+
}
|
|
2117
|
+
},
|
|
2118
|
+
{
|
|
2119
|
+
name: "listTokens",
|
|
2120
|
+
description: "List tokens in a category. Use 'tier' filter to get only semantic tokens (recommended) or primitives (reference only). Semantic tokens are the primary API; primitives are read-only reference values.",
|
|
2121
|
+
inputSchema: {
|
|
2122
|
+
type: "object",
|
|
2123
|
+
properties: {
|
|
2124
|
+
category: {
|
|
2125
|
+
type: "string",
|
|
2126
|
+
enum: ["colors", "typography", "spacing", "sizing", "shadows", "radius", "motion", "zIndex", "borders"],
|
|
2127
|
+
description: "Token category to list"
|
|
2128
|
+
},
|
|
2129
|
+
subcategory: {
|
|
2130
|
+
type: "string",
|
|
2131
|
+
description: "Optional subcategory, e.g., 'modes.light' for semantic colors, 'scale' for primitive spacing"
|
|
2132
|
+
},
|
|
2133
|
+
tier: {
|
|
2134
|
+
type: "string",
|
|
2135
|
+
enum: ["semantic", "primitive", "all"],
|
|
2136
|
+
description: "Filter by token tier. 'semantic' (recommended) returns purpose-driven tokens for styling. 'primitive' returns raw reference values. Default: 'all'"
|
|
2137
|
+
},
|
|
2138
|
+
tenantId: {
|
|
2139
|
+
type: "string",
|
|
2140
|
+
description: "Tenant ID for multi-tenant support (optional, defaults to 'default')"
|
|
2141
|
+
}
|
|
2142
|
+
},
|
|
2143
|
+
required: ["category"]
|
|
2144
|
+
}
|
|
2145
|
+
},
|
|
2146
|
+
{
|
|
2147
|
+
name: "getComponentTokens",
|
|
2148
|
+
description: "Get all design tokens used by a specific component (Button, Card, Dialog, etc.)",
|
|
2149
|
+
inputSchema: {
|
|
2150
|
+
type: "object",
|
|
2151
|
+
properties: {
|
|
2152
|
+
component: {
|
|
2153
|
+
type: "string",
|
|
2154
|
+
enum: ["button", "card", "dialog", "input", "select", "heading", "checkbox", "radio", "toggle", "selectionControls"],
|
|
2155
|
+
description: "Component name"
|
|
2156
|
+
},
|
|
2157
|
+
variant: {
|
|
2158
|
+
type: "string",
|
|
2159
|
+
description: "Optional variant name (e.g., 'primary', 'outline', 'ghost')"
|
|
2160
|
+
},
|
|
2161
|
+
size: {
|
|
2162
|
+
type: "string",
|
|
2163
|
+
description: "Optional size name (e.g., 'sm', 'md', 'lg')"
|
|
2164
|
+
},
|
|
2165
|
+
tenantId: {
|
|
2166
|
+
type: "string",
|
|
2167
|
+
description: "Tenant ID for multi-tenant support (optional, defaults to 'default')"
|
|
2168
|
+
}
|
|
2169
|
+
},
|
|
2170
|
+
required: ["component"]
|
|
2171
|
+
}
|
|
2172
|
+
},
|
|
2173
|
+
{
|
|
2174
|
+
name: "validateUsage",
|
|
2175
|
+
description: "Check if a CSS value follows the Atomix design system. Detects arbitrary values that should use tokens.",
|
|
2176
|
+
inputSchema: {
|
|
2177
|
+
type: "object",
|
|
2178
|
+
properties: {
|
|
2179
|
+
value: {
|
|
2180
|
+
type: "string",
|
|
2181
|
+
description: "CSS value to validate, e.g., '#ff0000', '16px', 'rgb(0,112,97)'"
|
|
2182
|
+
},
|
|
2183
|
+
context: {
|
|
2184
|
+
type: "string",
|
|
2185
|
+
enum: ["color", "spacing", "radius", "shadow", "typography", "any"],
|
|
2186
|
+
description: "Context of the value (helps find the right token)"
|
|
2187
|
+
}
|
|
2188
|
+
},
|
|
2189
|
+
required: ["value"]
|
|
2190
|
+
}
|
|
2191
|
+
},
|
|
2192
|
+
{
|
|
2193
|
+
name: "generateCursorRules",
|
|
2194
|
+
description: "[DEPRECATED] Use 'getAIToolRules' instead. Generate .cursorrules content for a project.",
|
|
2195
|
+
inputSchema: {
|
|
2196
|
+
type: "object",
|
|
2197
|
+
properties: {
|
|
2198
|
+
projectName: {
|
|
2199
|
+
type: "string",
|
|
2200
|
+
description: "Name of the project"
|
|
2201
|
+
},
|
|
2202
|
+
strict: {
|
|
2203
|
+
type: "boolean",
|
|
2204
|
+
description: "Whether to enforce strict token usage (no arbitrary values)"
|
|
2205
|
+
}
|
|
2206
|
+
},
|
|
2207
|
+
required: []
|
|
2208
|
+
}
|
|
2209
|
+
},
|
|
2210
|
+
{
|
|
2211
|
+
name: "getAIToolRules",
|
|
2212
|
+
description: "Generate design system rules for AI coding tools. Supports Cursor, GitHub Copilot, Windsurf, Cline, Continue, Zed, and more.",
|
|
2213
|
+
inputSchema: {
|
|
2214
|
+
type: "object",
|
|
2215
|
+
properties: {
|
|
2216
|
+
tool: {
|
|
2217
|
+
type: "string",
|
|
2218
|
+
enum: ["cursor", "copilot", "windsurf", "cline", "continue", "zed", "generic", "all"],
|
|
2219
|
+
description: "AI tool to generate rules for. Use 'all' to generate for all supported tools."
|
|
2220
|
+
},
|
|
2221
|
+
projectName: {
|
|
2222
|
+
type: "string",
|
|
2223
|
+
description: "Name of the project (default: 'My Project')"
|
|
2224
|
+
},
|
|
2225
|
+
strict: {
|
|
2226
|
+
type: "boolean",
|
|
2227
|
+
description: "Enforce strict token usage - no arbitrary values allowed (default: true)"
|
|
2228
|
+
}
|
|
2229
|
+
},
|
|
2230
|
+
required: ["tool"]
|
|
2231
|
+
}
|
|
2232
|
+
},
|
|
2233
|
+
{
|
|
2234
|
+
name: "listAITools",
|
|
2235
|
+
description: "List all supported AI coding tools and their rules file conventions.",
|
|
2236
|
+
inputSchema: {
|
|
2237
|
+
type: "object",
|
|
2238
|
+
properties: {},
|
|
2239
|
+
required: []
|
|
2240
|
+
}
|
|
2241
|
+
},
|
|
2242
|
+
{
|
|
2243
|
+
name: "getAIToolSetupGuide",
|
|
2244
|
+
description: "Get a complete setup guide for integrating Atomix with AI coding tools.",
|
|
2245
|
+
inputSchema: {
|
|
2246
|
+
type: "object",
|
|
2247
|
+
properties: {
|
|
2248
|
+
projectName: {
|
|
2249
|
+
type: "string",
|
|
2250
|
+
description: "Name of the project"
|
|
2251
|
+
}
|
|
2252
|
+
},
|
|
2253
|
+
required: []
|
|
2254
|
+
}
|
|
2255
|
+
},
|
|
2256
|
+
{
|
|
2257
|
+
name: "exportMCPConfig",
|
|
2258
|
+
description: "Generate MCP configuration file for AI tools. Creates ready-to-use config for Cursor (.cursor/mcp.json), Claude Desktop, Windsurf, Continue, or VS Code.",
|
|
2259
|
+
inputSchema: {
|
|
2260
|
+
type: "object",
|
|
2261
|
+
properties: {
|
|
2262
|
+
tool: {
|
|
2263
|
+
type: "string",
|
|
2264
|
+
enum: ["cursor", "claude-desktop", "windsurf", "continue", "vscode", "all"],
|
|
2265
|
+
description: "AI tool to generate MCP config for. Use 'all' to generate for all supported tools."
|
|
2266
|
+
},
|
|
2267
|
+
tenantId: {
|
|
2268
|
+
type: "string",
|
|
2269
|
+
description: "Tenant ID for multi-tenant setups (optional, defaults to 'default')"
|
|
2270
|
+
},
|
|
2271
|
+
projectName: {
|
|
2272
|
+
type: "string",
|
|
2273
|
+
description: "Project name for identification (optional)"
|
|
2274
|
+
},
|
|
2275
|
+
useNpx: {
|
|
2276
|
+
type: "boolean",
|
|
2277
|
+
description: "Use npx to run the server (default: true). Set to false for local development."
|
|
2278
|
+
}
|
|
2279
|
+
},
|
|
2280
|
+
required: ["tool"]
|
|
2281
|
+
}
|
|
2282
|
+
},
|
|
2283
|
+
{
|
|
2284
|
+
name: "getSetupInstructions",
|
|
2285
|
+
description: "Get detailed step-by-step setup instructions for a specific AI tool. Includes MCP configuration, rules file setup, and verification steps.",
|
|
2286
|
+
inputSchema: {
|
|
2287
|
+
type: "object",
|
|
2288
|
+
properties: {
|
|
2289
|
+
tool: {
|
|
2290
|
+
type: "string",
|
|
2291
|
+
enum: ["cursor", "copilot", "windsurf", "cline", "continue", "zed", "claude-desktop", "generic"],
|
|
2292
|
+
description: "AI tool to get setup instructions for."
|
|
2293
|
+
}
|
|
2294
|
+
},
|
|
2295
|
+
required: ["tool"]
|
|
2296
|
+
}
|
|
2297
|
+
},
|
|
2298
|
+
{
|
|
2299
|
+
name: "searchTokens",
|
|
2300
|
+
description: "Search for tokens by name or value. Results include tier metadata - prefer using 'semantic' tier tokens in code, use 'primitive' tier only for reference/validation.",
|
|
2301
|
+
inputSchema: {
|
|
2302
|
+
type: "object",
|
|
2303
|
+
properties: {
|
|
2304
|
+
query: {
|
|
2305
|
+
type: "string",
|
|
2306
|
+
description: "Search query (matches token paths or values)"
|
|
2307
|
+
},
|
|
2308
|
+
tier: {
|
|
2309
|
+
type: "string",
|
|
2310
|
+
enum: ["semantic", "primitive", "all"],
|
|
2311
|
+
description: "Filter results by tier. 'semantic' recommended for styling. Default: 'all'"
|
|
2312
|
+
}
|
|
2313
|
+
},
|
|
2314
|
+
required: ["query"]
|
|
2315
|
+
}
|
|
2316
|
+
}
|
|
2317
|
+
]
|
|
2318
|
+
};
|
|
2319
|
+
});
|
|
2320
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
2321
|
+
const { name, arguments: args } = request.params;
|
|
2322
|
+
switch (name) {
|
|
2323
|
+
case "getToken": {
|
|
2324
|
+
const path = args?.path;
|
|
2325
|
+
const value = getTokenByPath(primitives2, path);
|
|
2326
|
+
if (value === void 0) {
|
|
2327
|
+
return {
|
|
2328
|
+
content: [
|
|
2329
|
+
{
|
|
2330
|
+
type: "text",
|
|
2331
|
+
text: JSON.stringify({
|
|
2332
|
+
error: `Token not found: ${path}`,
|
|
2333
|
+
suggestion: `Use listTokens to see available tokens. Available categories: ${getTokenCategories().join(", ")}`
|
|
2334
|
+
}, null, 2)
|
|
2335
|
+
}
|
|
2336
|
+
]
|
|
2337
|
+
};
|
|
2338
|
+
}
|
|
2339
|
+
const cssVar = getCssVariableName(path);
|
|
2340
|
+
const metadata = getTokenMetadata(path);
|
|
2341
|
+
return {
|
|
2342
|
+
content: [
|
|
2343
|
+
{
|
|
2344
|
+
type: "text",
|
|
2345
|
+
text: JSON.stringify({
|
|
2346
|
+
path,
|
|
2347
|
+
value,
|
|
2348
|
+
cssVariable: cssVar,
|
|
2349
|
+
// Token tier classification
|
|
2350
|
+
tier: metadata.tier,
|
|
2351
|
+
mutable: metadata.mutable,
|
|
2352
|
+
editVia: metadata.editVia || null,
|
|
2353
|
+
guidance: metadata.guidance,
|
|
2354
|
+
// Usage examples
|
|
2355
|
+
usage: metadata.tier === "semantic" ? {
|
|
2356
|
+
css: `var(${cssVar})`,
|
|
2357
|
+
tailwind: getTailwindClass(path, value),
|
|
2358
|
+
recommendation: "Use this token in your components."
|
|
2359
|
+
} : {
|
|
2360
|
+
css: `var(${cssVar})`,
|
|
2361
|
+
tailwind: getTailwindClass(path, value),
|
|
2362
|
+
recommendation: "This is a primitive (read-only reference). Consider using a semantic token instead.",
|
|
2363
|
+
semanticAlternatives: getSuggestedSemanticTokens(path)
|
|
2364
|
+
}
|
|
2365
|
+
}, null, 2)
|
|
2366
|
+
}
|
|
2367
|
+
]
|
|
2368
|
+
};
|
|
2369
|
+
}
|
|
2370
|
+
case "listTokens": {
|
|
2371
|
+
const category = args?.category;
|
|
2372
|
+
const subcategory = args?.subcategory;
|
|
2373
|
+
const tierFilter = args?.tier || "all";
|
|
2374
|
+
const rawTokens = listTokensInCategory(primitives2, category, subcategory);
|
|
2375
|
+
const tokensWithMetadata = {};
|
|
2376
|
+
for (const [tokenPath, value] of Object.entries(rawTokens)) {
|
|
2377
|
+
const fullPath = subcategory ? `${category}.${subcategory}.${tokenPath}` : `${category}.${tokenPath}`;
|
|
2378
|
+
const metadata = getTokenMetadata(fullPath);
|
|
2379
|
+
if (tierFilter !== "all" && metadata.tier !== tierFilter) {
|
|
2380
|
+
continue;
|
|
2381
|
+
}
|
|
2382
|
+
tokensWithMetadata[tokenPath] = {
|
|
2383
|
+
value,
|
|
2384
|
+
tier: metadata.tier,
|
|
2385
|
+
mutable: metadata.mutable,
|
|
2386
|
+
guidance: metadata.guidance
|
|
2387
|
+
};
|
|
2388
|
+
}
|
|
2389
|
+
return {
|
|
2390
|
+
content: [
|
|
2391
|
+
{
|
|
2392
|
+
type: "text",
|
|
2393
|
+
text: JSON.stringify({
|
|
2394
|
+
category,
|
|
2395
|
+
subcategory: subcategory || null,
|
|
2396
|
+
tierFilter,
|
|
2397
|
+
count: Object.keys(tokensWithMetadata).length,
|
|
2398
|
+
note: tierFilter === "all" ? "Results include both primitive (read-only) and semantic (usable) tokens. Use tier='semantic' for styling recommendations." : tierFilter === "semantic" ? "Showing semantic tokens - these are the recommended tokens for styling." : "Showing primitive tokens - use these for reference/validation only, not direct styling.",
|
|
2399
|
+
tokens: tokensWithMetadata
|
|
2400
|
+
}, null, 2)
|
|
2401
|
+
}
|
|
2402
|
+
]
|
|
2403
|
+
};
|
|
2404
|
+
}
|
|
2405
|
+
case "getComponentTokens": {
|
|
2406
|
+
const component = args?.component;
|
|
2407
|
+
const variant = args?.variant;
|
|
2408
|
+
const size = args?.size;
|
|
2409
|
+
const componentKey = component.toLowerCase();
|
|
2410
|
+
const componentData = COMPONENT_TOKENS[componentKey];
|
|
2411
|
+
if (!componentData) {
|
|
2412
|
+
return {
|
|
2413
|
+
content: [
|
|
2414
|
+
{
|
|
2415
|
+
type: "text",
|
|
2416
|
+
text: JSON.stringify({
|
|
2417
|
+
error: `Component not found: ${component}`,
|
|
2418
|
+
available: Object.keys(COMPONENT_TOKENS)
|
|
2419
|
+
}, null, 2)
|
|
2420
|
+
}
|
|
2421
|
+
]
|
|
2422
|
+
};
|
|
2423
|
+
}
|
|
2424
|
+
let result = { ...componentData };
|
|
2425
|
+
if (variant && result.variants) {
|
|
2426
|
+
result.variants = { [variant]: result.variants[variant] };
|
|
2427
|
+
}
|
|
2428
|
+
if (size && result.sizes) {
|
|
2429
|
+
result.sizes = { [size]: result.sizes[size] };
|
|
2430
|
+
}
|
|
2431
|
+
return {
|
|
2432
|
+
content: [
|
|
2433
|
+
{
|
|
2434
|
+
type: "text",
|
|
2435
|
+
text: JSON.stringify(result, null, 2)
|
|
2436
|
+
}
|
|
2437
|
+
]
|
|
2438
|
+
};
|
|
2439
|
+
}
|
|
2440
|
+
case "validateUsage": {
|
|
2441
|
+
const value = args?.value;
|
|
2442
|
+
const context = args?.context || "any";
|
|
2443
|
+
const validation = validateValue(value, context);
|
|
2444
|
+
return {
|
|
2445
|
+
content: [
|
|
2446
|
+
{
|
|
2447
|
+
type: "text",
|
|
2448
|
+
text: JSON.stringify(validation, null, 2)
|
|
2449
|
+
}
|
|
2450
|
+
]
|
|
2451
|
+
};
|
|
2452
|
+
}
|
|
2453
|
+
case "generateCursorRules": {
|
|
2454
|
+
const projectName = args?.projectName || "My Project";
|
|
2455
|
+
const strict = args?.strict ?? true;
|
|
2456
|
+
const rules = generateCursorRules(projectName, strict);
|
|
2457
|
+
return {
|
|
2458
|
+
content: [
|
|
2459
|
+
{
|
|
2460
|
+
type: "text",
|
|
2461
|
+
text: `<!-- DEPRECATED: Use getAIToolRules instead -->
|
|
2462
|
+
${rules}`
|
|
2463
|
+
}
|
|
2464
|
+
]
|
|
2465
|
+
};
|
|
2466
|
+
}
|
|
2467
|
+
case "getAIToolRules": {
|
|
2468
|
+
const tool = args?.tool;
|
|
2469
|
+
const projectName = args?.projectName || "My Project";
|
|
2470
|
+
const strict = args?.strict ?? true;
|
|
2471
|
+
if (tool === "all") {
|
|
2472
|
+
const allRules = generateRulesForAllTools(projectName, strict);
|
|
2473
|
+
return {
|
|
2474
|
+
content: [
|
|
2475
|
+
{
|
|
2476
|
+
type: "text",
|
|
2477
|
+
text: JSON.stringify({
|
|
2478
|
+
message: `Generated rules for ${allRules.length} AI tools`,
|
|
2479
|
+
tools: allRules.map((r) => ({
|
|
2480
|
+
tool: r.tool.name,
|
|
2481
|
+
filename: r.filename,
|
|
2482
|
+
path: r.path,
|
|
2483
|
+
description: r.tool.description
|
|
2484
|
+
})),
|
|
2485
|
+
files: allRules.map((r) => ({
|
|
2486
|
+
path: r.path,
|
|
2487
|
+
content: r.content
|
|
2488
|
+
}))
|
|
2489
|
+
}, null, 2)
|
|
2490
|
+
}
|
|
2491
|
+
]
|
|
2492
|
+
};
|
|
2493
|
+
}
|
|
2494
|
+
try {
|
|
2495
|
+
const result = generateRulesForTool(tool, projectName, strict);
|
|
2496
|
+
return {
|
|
2497
|
+
content: [
|
|
2498
|
+
{
|
|
2499
|
+
type: "text",
|
|
2500
|
+
text: JSON.stringify({
|
|
2501
|
+
tool: result.tool.name,
|
|
2502
|
+
filename: result.filename,
|
|
2503
|
+
path: result.path,
|
|
2504
|
+
description: result.tool.description,
|
|
2505
|
+
content: result.content
|
|
2506
|
+
}, null, 2)
|
|
2507
|
+
}
|
|
2508
|
+
]
|
|
2509
|
+
};
|
|
2510
|
+
} catch (error) {
|
|
2511
|
+
return {
|
|
2512
|
+
content: [
|
|
2513
|
+
{
|
|
2514
|
+
type: "text",
|
|
2515
|
+
text: JSON.stringify({
|
|
2516
|
+
error: String(error),
|
|
2517
|
+
availableTools: Object.keys(AI_TOOLS)
|
|
2518
|
+
}, null, 2)
|
|
2519
|
+
}
|
|
2520
|
+
]
|
|
2521
|
+
};
|
|
2522
|
+
}
|
|
2523
|
+
}
|
|
2524
|
+
case "listAITools": {
|
|
2525
|
+
const tools = getSupportedAITools();
|
|
2526
|
+
return {
|
|
2527
|
+
content: [
|
|
2528
|
+
{
|
|
2529
|
+
type: "text",
|
|
2530
|
+
text: JSON.stringify({
|
|
2531
|
+
count: tools.length,
|
|
2532
|
+
tools: tools.map((t) => ({
|
|
2533
|
+
id: t.id,
|
|
2534
|
+
name: t.name,
|
|
2535
|
+
rulesFile: t.rulesPath,
|
|
2536
|
+
description: t.description
|
|
2537
|
+
})),
|
|
2538
|
+
note: "Use getAIToolRules({ tool: 'toolId' }) to generate rules for a specific tool."
|
|
2539
|
+
}, null, 2)
|
|
2540
|
+
}
|
|
2541
|
+
]
|
|
2542
|
+
};
|
|
2543
|
+
}
|
|
2544
|
+
case "getAIToolSetupGuide": {
|
|
2545
|
+
const projectName = args?.projectName || "My Project";
|
|
2546
|
+
const guide = generateToolSetupGuide(projectName);
|
|
2547
|
+
return {
|
|
2548
|
+
content: [
|
|
2549
|
+
{
|
|
2550
|
+
type: "text",
|
|
2551
|
+
text: guide
|
|
2552
|
+
}
|
|
2553
|
+
]
|
|
2554
|
+
};
|
|
2555
|
+
}
|
|
2556
|
+
case "exportMCPConfig": {
|
|
2557
|
+
const tool = args?.tool;
|
|
2558
|
+
const tenantId = args?.tenantId || "default";
|
|
2559
|
+
const projectName = args?.projectName || "my-project";
|
|
2560
|
+
const useNpx = args?.useNpx ?? true;
|
|
2561
|
+
const options = { tenantId, projectName, useNpx };
|
|
2562
|
+
if (tool === "all") {
|
|
2563
|
+
const allConfigs = generateAllMCPConfigs(options);
|
|
2564
|
+
return {
|
|
2565
|
+
content: [
|
|
2566
|
+
{
|
|
2567
|
+
type: "text",
|
|
2568
|
+
text: JSON.stringify({
|
|
2569
|
+
message: `Generated MCP configs for ${allConfigs.length} AI tools`,
|
|
2570
|
+
configs: allConfigs.map((c) => ({
|
|
2571
|
+
tool: c.tool,
|
|
2572
|
+
path: c.path,
|
|
2573
|
+
filename: c.filename
|
|
2574
|
+
})),
|
|
2575
|
+
files: allConfigs.map((c) => ({
|
|
2576
|
+
tool: c.tool,
|
|
2577
|
+
path: c.path,
|
|
2578
|
+
content: c.content,
|
|
2579
|
+
instructions: c.instructions
|
|
2580
|
+
}))
|
|
2581
|
+
}, null, 2)
|
|
2582
|
+
}
|
|
2583
|
+
]
|
|
2584
|
+
};
|
|
2585
|
+
}
|
|
2586
|
+
try {
|
|
2587
|
+
const config = generateMCPConfig(tool, options);
|
|
2588
|
+
return {
|
|
2589
|
+
content: [
|
|
2590
|
+
{
|
|
2591
|
+
type: "text",
|
|
2592
|
+
text: JSON.stringify({
|
|
2593
|
+
tool: config.tool,
|
|
2594
|
+
path: config.path,
|
|
2595
|
+
filename: config.filename,
|
|
2596
|
+
content: config.content,
|
|
2597
|
+
instructions: config.instructions
|
|
2598
|
+
}, null, 2)
|
|
2599
|
+
}
|
|
2600
|
+
]
|
|
2601
|
+
};
|
|
2602
|
+
} catch (error) {
|
|
2603
|
+
return {
|
|
2604
|
+
content: [
|
|
2605
|
+
{
|
|
2606
|
+
type: "text",
|
|
2607
|
+
text: JSON.stringify({
|
|
2608
|
+
error: String(error),
|
|
2609
|
+
availableTools: ["cursor", "claude-desktop", "windsurf", "continue", "vscode", "all"]
|
|
2610
|
+
}, null, 2)
|
|
2611
|
+
}
|
|
2612
|
+
]
|
|
2613
|
+
};
|
|
2614
|
+
}
|
|
2615
|
+
}
|
|
2616
|
+
case "getSetupInstructions": {
|
|
2617
|
+
const toolId = args?.tool;
|
|
2618
|
+
try {
|
|
2619
|
+
const instructions = getSetupInstructions(toolId);
|
|
2620
|
+
return {
|
|
2621
|
+
content: [
|
|
2622
|
+
{
|
|
2623
|
+
type: "text",
|
|
2624
|
+
text: instructions
|
|
2625
|
+
}
|
|
2626
|
+
]
|
|
2627
|
+
};
|
|
2628
|
+
} catch (error) {
|
|
2629
|
+
return {
|
|
2630
|
+
content: [
|
|
2631
|
+
{
|
|
2632
|
+
type: "text",
|
|
2633
|
+
text: JSON.stringify({
|
|
2634
|
+
error: String(error),
|
|
2635
|
+
availableTools: Object.keys(AI_TOOLS)
|
|
2636
|
+
}, null, 2)
|
|
2637
|
+
}
|
|
2638
|
+
]
|
|
2639
|
+
};
|
|
2640
|
+
}
|
|
2641
|
+
}
|
|
2642
|
+
case "searchTokens": {
|
|
2643
|
+
const query = (args?.query).toLowerCase();
|
|
2644
|
+
const tierFilter = args?.tier || "all";
|
|
2645
|
+
const allTokens = flattenTokens(primitives2);
|
|
2646
|
+
const matches = Object.entries(allTokens).filter(([path, value]) => {
|
|
2647
|
+
const pathLower = path.toLowerCase();
|
|
2648
|
+
const valueStr = String(value).toLowerCase();
|
|
2649
|
+
const matchesQuery = pathLower.includes(query) || valueStr.includes(query);
|
|
2650
|
+
if (!matchesQuery) return false;
|
|
2651
|
+
if (tierFilter !== "all") {
|
|
2652
|
+
const metadata = getTokenMetadata(path);
|
|
2653
|
+
if (metadata.tier !== tierFilter) return false;
|
|
2654
|
+
}
|
|
2655
|
+
return true;
|
|
2656
|
+
}).slice(0, 50).map(([path, value]) => {
|
|
2657
|
+
const metadata = getTokenMetadata(path);
|
|
2658
|
+
return {
|
|
2659
|
+
path,
|
|
2660
|
+
value,
|
|
2661
|
+
cssVariable: getCssVariableName(path),
|
|
2662
|
+
tier: metadata.tier,
|
|
2663
|
+
mutable: metadata.mutable,
|
|
2664
|
+
guidance: metadata.guidance
|
|
2665
|
+
};
|
|
2666
|
+
});
|
|
2667
|
+
matches.sort((a, b) => {
|
|
2668
|
+
if (a.tier === "semantic" && b.tier !== "semantic") return -1;
|
|
2669
|
+
if (a.tier !== "semantic" && b.tier === "semantic") return 1;
|
|
2670
|
+
return 0;
|
|
2671
|
+
});
|
|
2672
|
+
return {
|
|
2673
|
+
content: [
|
|
2674
|
+
{
|
|
2675
|
+
type: "text",
|
|
2676
|
+
text: JSON.stringify({
|
|
2677
|
+
query,
|
|
2678
|
+
tierFilter,
|
|
2679
|
+
count: matches.length,
|
|
2680
|
+
note: "Semantic tokens are listed first. Use semantic tokens for styling; primitives are for reference only.",
|
|
2681
|
+
matches
|
|
2682
|
+
}, null, 2)
|
|
2683
|
+
}
|
|
2684
|
+
]
|
|
2685
|
+
};
|
|
2686
|
+
}
|
|
2687
|
+
default:
|
|
2688
|
+
return {
|
|
2689
|
+
content: [
|
|
2690
|
+
{
|
|
2691
|
+
type: "text",
|
|
2692
|
+
text: JSON.stringify({ error: `Unknown tool: ${name}` })
|
|
2693
|
+
}
|
|
2694
|
+
]
|
|
2695
|
+
};
|
|
2696
|
+
}
|
|
2697
|
+
});
|
|
2698
|
+
server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
2699
|
+
return {
|
|
2700
|
+
resources: [
|
|
2701
|
+
{
|
|
2702
|
+
uri: "atomix://tokens/all",
|
|
2703
|
+
name: "All Atomix Tokens",
|
|
2704
|
+
description: "Complete design token reference",
|
|
2705
|
+
mimeType: "application/json"
|
|
2706
|
+
},
|
|
2707
|
+
{
|
|
2708
|
+
uri: "atomix://tokens/colors",
|
|
2709
|
+
name: "Color Tokens",
|
|
2710
|
+
description: "All color tokens (static, scales, modes)",
|
|
2711
|
+
mimeType: "application/json"
|
|
2712
|
+
},
|
|
2713
|
+
{
|
|
2714
|
+
uri: "atomix://tokens/typography",
|
|
2715
|
+
name: "Typography Tokens",
|
|
2716
|
+
description: "Font families, sizes, weights, line heights",
|
|
2717
|
+
mimeType: "application/json"
|
|
2718
|
+
},
|
|
2719
|
+
{
|
|
2720
|
+
uri: "atomix://tokens/spacing",
|
|
2721
|
+
name: "Spacing Tokens",
|
|
2722
|
+
description: "Spacing scale, insets, gaps",
|
|
2723
|
+
mimeType: "application/json"
|
|
2724
|
+
},
|
|
2725
|
+
{
|
|
2726
|
+
uri: "atomix://components",
|
|
2727
|
+
name: "Component Tokens",
|
|
2728
|
+
description: "Token mappings for all components",
|
|
2729
|
+
mimeType: "application/json"
|
|
2730
|
+
}
|
|
2731
|
+
]
|
|
2732
|
+
};
|
|
2733
|
+
});
|
|
2734
|
+
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
2735
|
+
const uri = request.params.uri;
|
|
2736
|
+
switch (uri) {
|
|
2737
|
+
case "atomix://tokens/all":
|
|
2738
|
+
return {
|
|
2739
|
+
contents: [
|
|
2740
|
+
{
|
|
2741
|
+
uri,
|
|
2742
|
+
mimeType: "application/json",
|
|
2743
|
+
text: JSON.stringify(primitives2, null, 2)
|
|
2744
|
+
}
|
|
2745
|
+
]
|
|
2746
|
+
};
|
|
2747
|
+
case "atomix://tokens/colors":
|
|
2748
|
+
return {
|
|
2749
|
+
contents: [
|
|
2750
|
+
{
|
|
2751
|
+
uri,
|
|
2752
|
+
mimeType: "application/json",
|
|
2753
|
+
text: JSON.stringify(primitives2.colors, null, 2)
|
|
2754
|
+
}
|
|
2755
|
+
]
|
|
2756
|
+
};
|
|
2757
|
+
case "atomix://tokens/typography":
|
|
2758
|
+
return {
|
|
2759
|
+
contents: [
|
|
2760
|
+
{
|
|
2761
|
+
uri,
|
|
2762
|
+
mimeType: "application/json",
|
|
2763
|
+
text: JSON.stringify(primitives2.typography, null, 2)
|
|
2764
|
+
}
|
|
2765
|
+
]
|
|
2766
|
+
};
|
|
2767
|
+
case "atomix://tokens/spacing":
|
|
2768
|
+
return {
|
|
2769
|
+
contents: [
|
|
2770
|
+
{
|
|
2771
|
+
uri,
|
|
2772
|
+
mimeType: "application/json",
|
|
2773
|
+
text: JSON.stringify(primitives2.spacing, null, 2)
|
|
2774
|
+
}
|
|
2775
|
+
]
|
|
2776
|
+
};
|
|
2777
|
+
case "atomix://components":
|
|
2778
|
+
return {
|
|
2779
|
+
contents: [
|
|
2780
|
+
{
|
|
2781
|
+
uri,
|
|
2782
|
+
mimeType: "application/json",
|
|
2783
|
+
text: JSON.stringify(COMPONENT_TOKENS, null, 2)
|
|
2784
|
+
}
|
|
2785
|
+
]
|
|
2786
|
+
};
|
|
2787
|
+
default:
|
|
2788
|
+
throw new Error(`Unknown resource: ${uri}`);
|
|
2789
|
+
}
|
|
2790
|
+
});
|
|
2791
|
+
function getTailwindClass(path, value) {
|
|
2792
|
+
if (path.startsWith("colors.static.brand.primary")) return "bg-brand text-brand";
|
|
2793
|
+
if (path.startsWith("spacing.") && !path.includes(".inset")) {
|
|
2794
|
+
const size = path.split(".").pop();
|
|
2795
|
+
return `p-${size} m-${size} gap-${size}`;
|
|
2796
|
+
}
|
|
2797
|
+
if (path.startsWith("radius.")) {
|
|
2798
|
+
const size = path.split(".").pop();
|
|
2799
|
+
return `rounded-${size}`;
|
|
2800
|
+
}
|
|
2801
|
+
return null;
|
|
2802
|
+
}
|
|
2803
|
+
function getSuggestedSemanticTokens(primitivePath) {
|
|
2804
|
+
const suggestions = [];
|
|
2805
|
+
if (primitivePath.startsWith("colors.scales.")) {
|
|
2806
|
+
suggestions.push(
|
|
2807
|
+
"colors.modes.light.bgPage (page background)",
|
|
2808
|
+
"colors.modes.light.bgSurface (card/panel background)",
|
|
2809
|
+
"colors.modes.light.textPrimary (main text)",
|
|
2810
|
+
"colors.modes.light.borderPrimary (borders)",
|
|
2811
|
+
"colors.modes.light.actionPrimary (interactive elements)"
|
|
2812
|
+
);
|
|
2813
|
+
}
|
|
2814
|
+
if (primitivePath.startsWith("spacing.")) {
|
|
2815
|
+
suggestions.push(
|
|
2816
|
+
"Use spacing tokens (spacing.xs, spacing.sm, spacing.md, spacing.lg, etc.)",
|
|
2817
|
+
"These resolve to CSS variables automatically"
|
|
2818
|
+
);
|
|
2819
|
+
}
|
|
2820
|
+
if (primitivePath.startsWith("typography.fontSize.")) {
|
|
2821
|
+
suggestions.push(
|
|
2822
|
+
"typography.typeSets.title-lg (large titles)",
|
|
2823
|
+
"typography.typeSets.title-md (medium titles)",
|
|
2824
|
+
"typography.typeSets.text-normal-regular (body text)",
|
|
2825
|
+
"typography.typeSets.label-md (form labels)"
|
|
2826
|
+
);
|
|
2827
|
+
}
|
|
2828
|
+
if (primitivePath.startsWith("radius.")) {
|
|
2829
|
+
suggestions.push(
|
|
2830
|
+
"Use radius tokens (radius.sm, radius.md, radius.lg, radius.full, etc.)",
|
|
2831
|
+
"Describe semantic usage in AI guidance (e.g., 'Buttons use @radius.md')"
|
|
2832
|
+
);
|
|
2833
|
+
}
|
|
2834
|
+
if (primitivePath.startsWith("shadows.elevation.")) {
|
|
2835
|
+
suggestions.push(
|
|
2836
|
+
"Use elevation keys (none, sm, md, lg, xl) in component defaults",
|
|
2837
|
+
"These resolve to CSS variables automatically"
|
|
2838
|
+
);
|
|
2839
|
+
}
|
|
2840
|
+
return suggestions;
|
|
2841
|
+
}
|
|
2842
|
+
function validateValue(value, context) {
|
|
2843
|
+
if (/^#[0-9A-Fa-f]{3,8}$/.test(value)) {
|
|
2844
|
+
const allTokens = flattenTokens(primitives2);
|
|
2845
|
+
const matches = Object.entries(allTokens).filter(([path, v]) => {
|
|
2846
|
+
if (typeof v !== "string") return false;
|
|
2847
|
+
return v.toLowerCase() === value.toLowerCase();
|
|
2848
|
+
}).map(([path, v]) => ({
|
|
2849
|
+
path,
|
|
2850
|
+
value: v,
|
|
2851
|
+
cssVariable: getCssVariableName(path)
|
|
2852
|
+
}));
|
|
2853
|
+
if (matches.length > 0) {
|
|
2854
|
+
return {
|
|
2855
|
+
valid: false,
|
|
2856
|
+
issue: "Hardcoded hex color detected",
|
|
2857
|
+
suggestion: `Use token instead: ${matches[0].cssVariable}`,
|
|
2858
|
+
matchingTokens: matches
|
|
2859
|
+
};
|
|
2860
|
+
}
|
|
2861
|
+
return {
|
|
2862
|
+
valid: false,
|
|
2863
|
+
issue: "Hardcoded hex color with no matching token",
|
|
2864
|
+
suggestion: "Check colors.static, colors.scales, or colors.modes for appropriate tokens"
|
|
2865
|
+
};
|
|
2866
|
+
}
|
|
2867
|
+
if (/^(rgb|rgba|hsl|hsla)\(/.test(value)) {
|
|
2868
|
+
return {
|
|
2869
|
+
valid: false,
|
|
2870
|
+
issue: "Hardcoded color function detected",
|
|
2871
|
+
suggestion: "Use CSS variable: var(--atomix-colors-*) or primitives.colors.*"
|
|
2872
|
+
};
|
|
2873
|
+
}
|
|
2874
|
+
if (context === "spacing" && /^\d+px$/.test(value)) {
|
|
2875
|
+
return {
|
|
2876
|
+
valid: false,
|
|
2877
|
+
issue: "Hardcoded pixel value for spacing",
|
|
2878
|
+
suggestion: "Use spacing.* tokens (e.g., @spacing.md, @spacing.lg)"
|
|
2879
|
+
};
|
|
2880
|
+
}
|
|
2881
|
+
if (/^\d+px$/.test(value)) {
|
|
2882
|
+
return {
|
|
2883
|
+
valid: false,
|
|
2884
|
+
issue: "Hardcoded pixel value detected",
|
|
2885
|
+
suggestion: "Consider using design tokens from spacing, sizing, or typography"
|
|
2886
|
+
};
|
|
2887
|
+
}
|
|
2888
|
+
if (/\[.*\]/.test(value)) {
|
|
2889
|
+
return {
|
|
2890
|
+
valid: false,
|
|
2891
|
+
issue: "Tailwind arbitrary value detected",
|
|
2892
|
+
suggestion: "Replace with token-based class or CSS variable"
|
|
2893
|
+
};
|
|
2894
|
+
}
|
|
2895
|
+
return { valid: true };
|
|
2896
|
+
}
|
|
2897
|
+
var primitives2 = {};
|
|
2898
|
+
var userGovernance;
|
|
2899
|
+
var isUserMode = false;
|
|
2900
|
+
var userDsId;
|
|
2901
|
+
async function main() {
|
|
2902
|
+
const cliArgs = parseCLIArgs();
|
|
2903
|
+
if (isUserDSMode(cliArgs)) {
|
|
2904
|
+
console.error(`[atomix-mcp] User DS mode: loading design system ${cliArgs.dsId}`);
|
|
2905
|
+
isUserMode = true;
|
|
2906
|
+
userDsId = cliArgs.dsId;
|
|
2907
|
+
const result = await fetchUserDesignSystem({
|
|
2908
|
+
dsId: cliArgs.dsId,
|
|
2909
|
+
apiKey: cliArgs.apiKey,
|
|
2910
|
+
baseUrl: cliArgs.baseUrl
|
|
2911
|
+
});
|
|
2912
|
+
if (!result.success || !result.tokens) {
|
|
2913
|
+
console.error(`[atomix-mcp] Failed to load user DS: ${result.error}`);
|
|
2914
|
+
console.error("[atomix-mcp] Falling back to Atomix internal tokens");
|
|
2915
|
+
primitives2 = await loadPrimitives();
|
|
2916
|
+
} else {
|
|
2917
|
+
primitives2 = transformUserTokens(result.tokens);
|
|
2918
|
+
userGovernance = result.governance;
|
|
2919
|
+
const meta = result.meta;
|
|
2920
|
+
const dsName = meta?.name || cliArgs.dsId;
|
|
2921
|
+
const tokenCategories = Object.keys(primitives2);
|
|
2922
|
+
const rulesCount = userGovernance?.rules?.length || 0;
|
|
2923
|
+
console.error("");
|
|
2924
|
+
console.error(`[atomix-mcp] ========================================`);
|
|
2925
|
+
console.error(`[atomix-mcp] Design System: ${dsName}`);
|
|
2926
|
+
console.error(`[atomix-mcp] ----------------------------------------`);
|
|
2927
|
+
if (meta?.publishedAt) {
|
|
2928
|
+
const publishedDate = new Date(meta.publishedAt);
|
|
2929
|
+
const timeAgo = formatTimeAgo(meta.publishedAt);
|
|
2930
|
+
console.error(`[atomix-mcp] Published: ${timeAgo}`);
|
|
2931
|
+
console.error(`[atomix-mcp] (${publishedDate.toLocaleString()})`);
|
|
2932
|
+
}
|
|
2933
|
+
if (meta?.version) {
|
|
2934
|
+
console.error(`[atomix-mcp] Version: ${meta.version}`);
|
|
2935
|
+
}
|
|
2936
|
+
console.error(`[atomix-mcp] ----------------------------------------`);
|
|
2937
|
+
console.error(`[atomix-mcp] Tokens: ${tokenCategories.length} categories`);
|
|
2938
|
+
console.error(`[atomix-mcp] ${tokenCategories.join(", ")}`);
|
|
2939
|
+
console.error(`[atomix-mcp] Rules: ${rulesCount} governance rules`);
|
|
2940
|
+
console.error(`[atomix-mcp] ========================================`);
|
|
2941
|
+
console.error("");
|
|
2942
|
+
}
|
|
2943
|
+
} else {
|
|
2944
|
+
console.error("[atomix-mcp] Loading Atomix internal primitives...");
|
|
2945
|
+
primitives2 = await loadPrimitives();
|
|
2946
|
+
console.error(`[atomix-mcp] Loaded ${Object.keys(primitives2).length} token categories`);
|
|
2947
|
+
}
|
|
2948
|
+
const transport = new StdioServerTransport();
|
|
2949
|
+
await server.connect(transport);
|
|
2950
|
+
console.error("[atomix-mcp] Atomix MCP server started");
|
|
2951
|
+
if (isUserMode) {
|
|
2952
|
+
console.error(`[atomix-mcp] Serving design system: ${userDsId}`);
|
|
2953
|
+
}
|
|
2954
|
+
}
|
|
2955
|
+
main().catch((error) => {
|
|
2956
|
+
console.error("[atomix-mcp] Fatal error:", error);
|
|
2957
|
+
process.exit(1);
|
|
2958
|
+
});
|
|
2959
|
+
export {
|
|
2960
|
+
AI_TOOLS,
|
|
2961
|
+
fetchUserDesignSystem,
|
|
2962
|
+
generateAllMCPConfigs,
|
|
2963
|
+
generateCursorRules,
|
|
2964
|
+
generateMCPConfig,
|
|
2965
|
+
generateRulesForAllTools,
|
|
2966
|
+
generateRulesForTool,
|
|
2967
|
+
generateToolSetupGuide,
|
|
2968
|
+
getSetupInstructions,
|
|
2969
|
+
getSupportedAITools,
|
|
2970
|
+
isUserDSMode,
|
|
2971
|
+
parseCLIArgs,
|
|
2972
|
+
transformUserTokens
|
|
2973
|
+
};
|
|
2974
|
+
//# sourceMappingURL=index.js.map
|