@atomixstudio/mcp 0.1.0 → 1.0.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 +72 -288
- package/dist/index.d.ts +1 -201
- package/dist/index.js +1288 -2740
- package/dist/index.js.map +1 -1
- package/package.json +30 -30
- package/data/component-tokens-snapshot.json +0 -659
- package/data/tenants/default.json +0 -73
- package/scripts/sync-component-tokens.cjs +0 -974
- package/scripts/sync-component-tokens.js +0 -678
- package/src/ai-rules-generator.ts +0 -1144
- package/src/component-tokens.ts +0 -702
- package/src/index.ts +0 -1155
- package/src/tenant-store.ts +0 -436
- package/src/tokens.ts +0 -208
- package/src/user-tokens.ts +0 -268
- package/src/utils.ts +0 -465
- package/tests/stress-test.cjs +0 -907
- package/tsconfig.json +0 -21
- package/tsup.config.ts +0 -16
package/dist/index.js
CHANGED
|
@@ -7,2090 +7,155 @@ import {
|
|
|
7
7
|
CallToolRequestSchema,
|
|
8
8
|
ListToolsRequestSchema,
|
|
9
9
|
ListResourcesRequestSchema,
|
|
10
|
-
ReadResourceRequestSchema
|
|
10
|
+
ReadResourceRequestSchema,
|
|
11
|
+
ListPromptsRequestSchema,
|
|
12
|
+
GetPromptRequestSchema
|
|
11
13
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
import
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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
|
-
`;
|
|
14
|
+
import * as fs from "fs";
|
|
15
|
+
import * as path from "path";
|
|
16
|
+
import * as readline from "readline";
|
|
17
|
+
function parseArgs() {
|
|
18
|
+
const args = process.argv.slice(2);
|
|
19
|
+
let command = "server";
|
|
20
|
+
let dsId2 = null;
|
|
21
|
+
let apiKey2 = null;
|
|
22
|
+
let apiBase2 = null;
|
|
23
|
+
let output = null;
|
|
24
|
+
let format = null;
|
|
25
|
+
let exclude = [];
|
|
26
|
+
let yes = false;
|
|
27
|
+
if (args[0] && !args[0].startsWith("-")) {
|
|
28
|
+
const cmd = args[0].toLowerCase();
|
|
29
|
+
if (cmd === "sync") command = "sync";
|
|
30
|
+
else if (cmd === "init") command = "init";
|
|
31
|
+
else if (cmd === "help" || cmd === "--help" || cmd === "-h") command = "help";
|
|
32
|
+
}
|
|
33
|
+
for (let i = 0; i < args.length; i++) {
|
|
34
|
+
if (args[i] === "--ds-id" && args[i + 1]) {
|
|
35
|
+
dsId2 = args[i + 1];
|
|
36
|
+
i++;
|
|
37
|
+
} else if (args[i] === "--api-key" && args[i + 1]) {
|
|
38
|
+
apiKey2 = args[i + 1];
|
|
39
|
+
i++;
|
|
40
|
+
} else if (args[i] === "--api-base" && args[i + 1]) {
|
|
41
|
+
apiBase2 = args[i + 1];
|
|
42
|
+
i++;
|
|
43
|
+
} else if ((args[i] === "--output" || args[i] === "-o") && args[i + 1]) {
|
|
44
|
+
output = args[i + 1];
|
|
45
|
+
i++;
|
|
46
|
+
} else if (args[i] === "--format" && args[i + 1]) {
|
|
47
|
+
const f = args[i + 1].toLowerCase();
|
|
48
|
+
const validFormats = ["css", "scss", "less", "json", "ts", "js", "swift", "kotlin", "dart"];
|
|
49
|
+
if (validFormats.includes(f)) format = f;
|
|
50
|
+
i++;
|
|
51
|
+
} else if (args[i] === "--exclude" && args[i + 1]) {
|
|
52
|
+
exclude.push(args[i + 1]);
|
|
53
|
+
i++;
|
|
54
|
+
} else if (args[i] === "-y" || args[i] === "--yes") {
|
|
55
|
+
yes = true;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return { command, dsId: dsId2, apiKey: apiKey2, apiBase: apiBase2, output, format, exclude, yes };
|
|
1969
59
|
}
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
60
|
+
var cliArgs = parseArgs();
|
|
61
|
+
var { dsId, apiKey } = cliArgs;
|
|
62
|
+
var apiBase = cliArgs.apiBase || "https://atomixstudio.eu";
|
|
63
|
+
var cachedData = null;
|
|
64
|
+
async function fetchDesignSystem() {
|
|
65
|
+
if (cachedData) return cachedData;
|
|
66
|
+
if (!dsId) {
|
|
67
|
+
throw new Error("Missing --ds-id argument. Usage: npx @atomixstudio/mcp --ds-id <id> --api-key <key>");
|
|
1974
68
|
}
|
|
1975
|
-
const
|
|
1976
|
-
|
|
1977
|
-
|
|
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
|
|
69
|
+
const url = `${apiBase}/api/ds/${dsId}/tokens?format=export`;
|
|
70
|
+
const headers = {
|
|
71
|
+
"Content-Type": "application/json"
|
|
1987
72
|
};
|
|
73
|
+
if (apiKey) {
|
|
74
|
+
headers["x-api-key"] = apiKey;
|
|
75
|
+
}
|
|
76
|
+
const response = await fetch(url, { headers });
|
|
77
|
+
if (!response.ok) {
|
|
78
|
+
const text = await response.text();
|
|
79
|
+
throw new Error(`Failed to fetch design system: ${response.status} ${text}`);
|
|
80
|
+
}
|
|
81
|
+
const data = await response.json();
|
|
82
|
+
cachedData = data;
|
|
83
|
+
return data;
|
|
1988
84
|
}
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
85
|
+
var TOKEN_CATEGORIES = ["colors", "typography", "spacing", "sizing", "shadows", "radius", "borders", "motion", "zIndex"];
|
|
86
|
+
function getTokenByPath(tokens, path2) {
|
|
87
|
+
const parts = path2.split(".");
|
|
88
|
+
let current = tokens;
|
|
89
|
+
for (const part of parts) {
|
|
90
|
+
if (current && typeof current === "object" && part in current) {
|
|
91
|
+
current = current[part];
|
|
92
|
+
} else {
|
|
93
|
+
return void 0;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return current;
|
|
1996
97
|
}
|
|
1997
|
-
function
|
|
1998
|
-
const
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
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
|
-
`;
|
|
98
|
+
function flattenTokens(obj, prefix = "") {
|
|
99
|
+
const results = [];
|
|
100
|
+
if (obj && typeof obj === "object" && !Array.isArray(obj)) {
|
|
101
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
102
|
+
const newPath = prefix ? `${prefix}.${key}` : key;
|
|
103
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
104
|
+
results.push(...flattenTokens(value, newPath));
|
|
105
|
+
} else {
|
|
106
|
+
results.push({ path: newPath, value });
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return results;
|
|
2064
111
|
}
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
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
|
|
112
|
+
function searchTokens(tokens, query) {
|
|
113
|
+
const flat = flattenTokens(tokens);
|
|
114
|
+
const lowerQuery = query.toLowerCase();
|
|
115
|
+
return flat.filter(({ path: path2, value }) => {
|
|
116
|
+
const pathMatch = path2.toLowerCase().includes(lowerQuery);
|
|
117
|
+
const valueMatch = String(value).toLowerCase().includes(lowerQuery);
|
|
118
|
+
return pathMatch || valueMatch;
|
|
2083
119
|
});
|
|
2084
120
|
}
|
|
121
|
+
function countTokens(tokens, prefix = "") {
|
|
122
|
+
let count = 0;
|
|
123
|
+
for (const [key, value] of Object.entries(tokens)) {
|
|
124
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
125
|
+
count += countTokens(value, `${prefix}${key}.`);
|
|
126
|
+
} else if (value !== void 0 && value !== null) {
|
|
127
|
+
count++;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return count;
|
|
131
|
+
}
|
|
132
|
+
function getTokenStats(data) {
|
|
133
|
+
const byCategory = {};
|
|
134
|
+
let total = 0;
|
|
135
|
+
for (const [category, value] of Object.entries(data.tokens)) {
|
|
136
|
+
if (value && typeof value === "object") {
|
|
137
|
+
const count = countTokens(value);
|
|
138
|
+
byCategory[category] = count;
|
|
139
|
+
total += count;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return {
|
|
143
|
+
total,
|
|
144
|
+
byCategory,
|
|
145
|
+
cssVariables: Object.keys(data.cssVariables).length,
|
|
146
|
+
governanceRules: data.governance.rules.length
|
|
147
|
+
};
|
|
148
|
+
}
|
|
2085
149
|
var server = new Server(
|
|
2086
150
|
{
|
|
2087
|
-
name: "atomix-mcp",
|
|
2088
|
-
version: "
|
|
151
|
+
name: "atomix-mcp-user",
|
|
152
|
+
version: "1.0.0"
|
|
2089
153
|
},
|
|
2090
154
|
{
|
|
2091
155
|
capabilities: {
|
|
2092
156
|
tools: {},
|
|
2093
|
-
resources: {}
|
|
157
|
+
resources: {},
|
|
158
|
+
prompts: {}
|
|
2094
159
|
}
|
|
2095
160
|
}
|
|
2096
161
|
);
|
|
@@ -2099,17 +164,13 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
2099
164
|
tools: [
|
|
2100
165
|
{
|
|
2101
166
|
name: "getToken",
|
|
2102
|
-
description: "Get a specific design token by its path. Returns value
|
|
167
|
+
description: "Get a specific design token by its path. Returns the value and CSS variable name.",
|
|
2103
168
|
inputSchema: {
|
|
2104
169
|
type: "object",
|
|
2105
170
|
properties: {
|
|
2106
171
|
path: {
|
|
2107
172
|
type: "string",
|
|
2108
|
-
description: "Token path in dot notation.
|
|
2109
|
-
},
|
|
2110
|
-
tenantId: {
|
|
2111
|
-
type: "string",
|
|
2112
|
-
description: "Tenant ID for multi-tenant support (optional, defaults to 'default')"
|
|
173
|
+
description: "Token path in dot notation (e.g., 'colors.brand.primary', 'spacing.scale.md')"
|
|
2113
174
|
}
|
|
2114
175
|
},
|
|
2115
176
|
required: ["path"]
|
|
@@ -2117,164 +178,81 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
2117
178
|
},
|
|
2118
179
|
{
|
|
2119
180
|
name: "listTokens",
|
|
2120
|
-
description: "List tokens in a category
|
|
181
|
+
description: "List all tokens in a category (colors, typography, spacing, sizing, shadows, radius, borders, motion, zIndex).",
|
|
2121
182
|
inputSchema: {
|
|
2122
183
|
type: "object",
|
|
2123
184
|
properties: {
|
|
2124
185
|
category: {
|
|
2125
186
|
type: "string",
|
|
2126
|
-
enum:
|
|
187
|
+
enum: TOKEN_CATEGORIES,
|
|
2127
188
|
description: "Token category to list"
|
|
2128
189
|
},
|
|
2129
190
|
subcategory: {
|
|
2130
191
|
type: "string",
|
|
2131
|
-
description: "Optional subcategory
|
|
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')"
|
|
192
|
+
description: "Optional subcategory (e.g., 'brand' for colors, 'scale' for spacing)"
|
|
2141
193
|
}
|
|
2142
194
|
},
|
|
2143
195
|
required: ["category"]
|
|
2144
196
|
}
|
|
2145
197
|
},
|
|
2146
198
|
{
|
|
2147
|
-
name: "
|
|
2148
|
-
description: "
|
|
199
|
+
name: "searchTokens",
|
|
200
|
+
description: "Search for tokens by name or value.",
|
|
2149
201
|
inputSchema: {
|
|
2150
202
|
type: "object",
|
|
2151
203
|
properties: {
|
|
2152
|
-
|
|
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: {
|
|
204
|
+
query: {
|
|
2166
205
|
type: "string",
|
|
2167
|
-
description: "
|
|
206
|
+
description: "Search query (matches token paths or values)"
|
|
2168
207
|
}
|
|
2169
208
|
},
|
|
2170
|
-
required: ["
|
|
209
|
+
required: ["query"]
|
|
2171
210
|
}
|
|
2172
211
|
},
|
|
2173
212
|
{
|
|
2174
213
|
name: "validateUsage",
|
|
2175
|
-
description: "Check if a CSS value follows the
|
|
214
|
+
description: "Check if a CSS value follows the design system. Detects hardcoded values that should use tokens.",
|
|
2176
215
|
inputSchema: {
|
|
2177
216
|
type: "object",
|
|
2178
217
|
properties: {
|
|
2179
218
|
value: {
|
|
2180
219
|
type: "string",
|
|
2181
|
-
description: "CSS value to validate
|
|
220
|
+
description: "CSS value to validate (e.g., '#ff0000', '16px', 'rgb(0,112,97)')"
|
|
2182
221
|
},
|
|
2183
222
|
context: {
|
|
2184
223
|
type: "string",
|
|
2185
224
|
enum: ["color", "spacing", "radius", "shadow", "typography", "any"],
|
|
2186
|
-
description: "Context of the value
|
|
225
|
+
description: "Context of the value to help find the right token"
|
|
2187
226
|
}
|
|
2188
227
|
},
|
|
2189
228
|
required: ["value"]
|
|
2190
229
|
}
|
|
2191
230
|
},
|
|
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
231
|
{
|
|
2211
232
|
name: "getAIToolRules",
|
|
2212
|
-
description: "Generate design system rules for AI coding tools
|
|
233
|
+
description: "Generate design system rules for AI coding tools (Cursor, Copilot, Windsurf, etc.).",
|
|
2213
234
|
inputSchema: {
|
|
2214
235
|
type: "object",
|
|
2215
236
|
properties: {
|
|
2216
237
|
tool: {
|
|
2217
238
|
type: "string",
|
|
2218
239
|
enum: ["cursor", "copilot", "windsurf", "cline", "continue", "zed", "generic", "all"],
|
|
2219
|
-
description: "AI tool to generate rules for. Use 'all' to
|
|
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)"
|
|
240
|
+
description: "AI tool to generate rules for. Use 'all' to get rules for all tools."
|
|
2228
241
|
}
|
|
2229
242
|
},
|
|
2230
243
|
required: ["tool"]
|
|
2231
244
|
}
|
|
2232
245
|
},
|
|
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
246
|
{
|
|
2257
247
|
name: "exportMCPConfig",
|
|
2258
|
-
description: "Generate MCP configuration file for AI tools.
|
|
248
|
+
description: "Generate MCP configuration file for AI tools.",
|
|
2259
249
|
inputSchema: {
|
|
2260
250
|
type: "object",
|
|
2261
251
|
properties: {
|
|
2262
252
|
tool: {
|
|
2263
253
|
type: "string",
|
|
2264
254
|
enum: ["cursor", "claude-desktop", "windsurf", "continue", "vscode", "all"],
|
|
2265
|
-
description: "AI tool to generate MCP config for.
|
|
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."
|
|
255
|
+
description: "AI tool to generate MCP config for."
|
|
2278
256
|
}
|
|
2279
257
|
},
|
|
2280
258
|
required: ["tool"]
|
|
@@ -2282,7 +260,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
2282
260
|
},
|
|
2283
261
|
{
|
|
2284
262
|
name: "getSetupInstructions",
|
|
2285
|
-
description: "Get detailed
|
|
263
|
+
description: "Get detailed setup instructions for a specific AI tool.",
|
|
2286
264
|
inputSchema: {
|
|
2287
265
|
type: "object",
|
|
2288
266
|
properties: {
|
|
@@ -2294,681 +272,1251 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
2294
272
|
},
|
|
2295
273
|
required: ["tool"]
|
|
2296
274
|
}
|
|
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
275
|
}
|
|
2317
276
|
]
|
|
2318
277
|
};
|
|
2319
278
|
});
|
|
2320
279
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
2321
280
|
const { name, arguments: args } = request.params;
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
281
|
+
try {
|
|
282
|
+
const data = await fetchDesignSystem();
|
|
283
|
+
switch (name) {
|
|
284
|
+
case "getToken": {
|
|
285
|
+
const path2 = args?.path;
|
|
286
|
+
const value = getTokenByPath(data.tokens, path2);
|
|
287
|
+
if (value === void 0) {
|
|
288
|
+
return {
|
|
289
|
+
content: [{
|
|
2330
290
|
type: "text",
|
|
2331
291
|
text: JSON.stringify({
|
|
2332
|
-
error: `Token not found: ${
|
|
2333
|
-
suggestion:
|
|
292
|
+
error: `Token not found: ${path2}`,
|
|
293
|
+
suggestion: "Use listTokens or searchTokens to find available tokens.",
|
|
294
|
+
availableCategories: TOKEN_CATEGORIES
|
|
2334
295
|
}, null, 2)
|
|
2335
|
-
}
|
|
2336
|
-
|
|
2337
|
-
}
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
content: [
|
|
2343
|
-
{
|
|
296
|
+
}]
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
const cssVarKey = `--atmx-${path2.replace(/\./g, "-")}`;
|
|
300
|
+
const cssVar = data.cssVariables[cssVarKey];
|
|
301
|
+
return {
|
|
302
|
+
content: [{
|
|
2344
303
|
type: "text",
|
|
2345
304
|
text: JSON.stringify({
|
|
2346
|
-
path,
|
|
305
|
+
path: path2,
|
|
2347
306
|
value,
|
|
2348
|
-
cssVariable: cssVar
|
|
2349
|
-
|
|
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
|
-
}
|
|
307
|
+
cssVariable: cssVar || `var(${cssVarKey})`,
|
|
308
|
+
usage: `style={{ property: "var(${cssVarKey})" }}`
|
|
2365
309
|
}, 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
|
|
310
|
+
}]
|
|
2387
311
|
};
|
|
2388
312
|
}
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
313
|
+
case "listTokens": {
|
|
314
|
+
const category = args?.category;
|
|
315
|
+
const subcategory = args?.subcategory;
|
|
316
|
+
let tokensToList = data.tokens[category];
|
|
317
|
+
if (subcategory && tokensToList && typeof tokensToList === "object") {
|
|
318
|
+
tokensToList = getTokenByPath(tokensToList, subcategory);
|
|
319
|
+
}
|
|
320
|
+
if (!tokensToList) {
|
|
321
|
+
return {
|
|
322
|
+
content: [{
|
|
323
|
+
type: "text",
|
|
324
|
+
text: JSON.stringify({
|
|
325
|
+
error: `Category not found: ${category}${subcategory ? `.${subcategory}` : ""}`,
|
|
326
|
+
availableCategories: TOKEN_CATEGORIES
|
|
327
|
+
}, null, 2)
|
|
328
|
+
}]
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
const flat = flattenTokens(tokensToList);
|
|
332
|
+
return {
|
|
333
|
+
content: [{
|
|
2392
334
|
type: "text",
|
|
2393
335
|
text: JSON.stringify({
|
|
2394
336
|
category,
|
|
2395
|
-
subcategory
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
337
|
+
subcategory,
|
|
338
|
+
count: flat.length,
|
|
339
|
+
tokens: flat.slice(0, 50),
|
|
340
|
+
// Limit to 50 for readability
|
|
341
|
+
truncated: flat.length > 50
|
|
2400
342
|
}, 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
|
-
]
|
|
343
|
+
}]
|
|
2422
344
|
};
|
|
2423
345
|
}
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
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);
|
|
346
|
+
case "searchTokens": {
|
|
347
|
+
const query = args?.query;
|
|
348
|
+
const results = searchTokens(data.tokens, query);
|
|
2473
349
|
return {
|
|
2474
|
-
content: [
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
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
|
-
]
|
|
350
|
+
content: [{
|
|
351
|
+
type: "text",
|
|
352
|
+
text: JSON.stringify({
|
|
353
|
+
query,
|
|
354
|
+
count: results.length,
|
|
355
|
+
results: results.slice(0, 30),
|
|
356
|
+
truncated: results.length > 30
|
|
357
|
+
}, null, 2)
|
|
358
|
+
}]
|
|
2492
359
|
};
|
|
2493
360
|
}
|
|
2494
|
-
|
|
2495
|
-
const
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
361
|
+
case "validateUsage": {
|
|
362
|
+
const value = args?.value;
|
|
363
|
+
const context = args?.context || "any";
|
|
364
|
+
const isHexColor = /^#[0-9A-Fa-f]{3,8}$/.test(value);
|
|
365
|
+
const isRgbColor = /^rgb\(|^rgba\(|^hsl\(/.test(value);
|
|
366
|
+
const isPixelValue = /^\d+px$/.test(value);
|
|
367
|
+
if (!isHexColor && !isRgbColor && !isPixelValue) {
|
|
368
|
+
return {
|
|
369
|
+
content: [{
|
|
2499
370
|
type: "text",
|
|
2500
371
|
text: JSON.stringify({
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
description: result.tool.description,
|
|
2505
|
-
content: result.content
|
|
372
|
+
value,
|
|
373
|
+
valid: true,
|
|
374
|
+
message: "Value appears to be using tokens or is not a design token value."
|
|
2506
375
|
}, null, 2)
|
|
2507
|
-
}
|
|
2508
|
-
|
|
2509
|
-
}
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
{
|
|
376
|
+
}]
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
const matches = searchTokens(data.tokens, value);
|
|
380
|
+
if (matches.length > 0) {
|
|
381
|
+
return {
|
|
382
|
+
content: [{
|
|
2514
383
|
type: "text",
|
|
2515
384
|
text: JSON.stringify({
|
|
2516
|
-
|
|
2517
|
-
|
|
385
|
+
value,
|
|
386
|
+
valid: false,
|
|
387
|
+
message: "Hardcoded value detected. Use a token instead.",
|
|
388
|
+
matchingTokens: matches.slice(0, 5),
|
|
389
|
+
suggestion: `Use var(--atmx-${matches[0].path.replace(/\./g, "-")}) instead of ${value}`
|
|
2518
390
|
}, null, 2)
|
|
2519
|
-
}
|
|
2520
|
-
|
|
2521
|
-
}
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
case "listAITools": {
|
|
2525
|
-
const tools = getSupportedAITools();
|
|
2526
|
-
return {
|
|
2527
|
-
content: [
|
|
2528
|
-
{
|
|
391
|
+
}]
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
return {
|
|
395
|
+
content: [{
|
|
2529
396
|
type: "text",
|
|
2530
397
|
text: JSON.stringify({
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
description: t.description
|
|
2537
|
-
})),
|
|
2538
|
-
note: "Use getAIToolRules({ tool: 'toolId' }) to generate rules for a specific tool."
|
|
398
|
+
value,
|
|
399
|
+
valid: false,
|
|
400
|
+
message: "Hardcoded value detected. No exact token match found.",
|
|
401
|
+
suggestion: `Consider adding this value to the design system or use the closest token.`,
|
|
402
|
+
context
|
|
2539
403
|
}, null, 2)
|
|
404
|
+
}]
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
case "getAIToolRules": {
|
|
408
|
+
const tool = args?.tool;
|
|
409
|
+
const rulesUrl = `${apiBase}/api/ds/${dsId}/rules?format=${tool === "all" ? "all" : tool}`;
|
|
410
|
+
console.error(`[getAIToolRules] Fetching: ${rulesUrl}`);
|
|
411
|
+
const headers = { "Content-Type": "application/json" };
|
|
412
|
+
if (apiKey) headers["x-api-key"] = apiKey;
|
|
413
|
+
try {
|
|
414
|
+
const response = await fetch(rulesUrl, { headers });
|
|
415
|
+
console.error(`[getAIToolRules] Response status: ${response.status}`);
|
|
416
|
+
if (!response.ok) {
|
|
417
|
+
const errorText = await response.text();
|
|
418
|
+
console.error(`[getAIToolRules] Error response: ${errorText}`);
|
|
419
|
+
throw new Error(`Failed to fetch rules: ${response.status} - ${errorText}`);
|
|
2540
420
|
}
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
421
|
+
const rules = await response.json();
|
|
422
|
+
console.error(`[getAIToolRules] Got ${rules.rules?.length || 0} rules`);
|
|
423
|
+
return {
|
|
424
|
+
content: [{
|
|
425
|
+
type: "text",
|
|
426
|
+
text: JSON.stringify(rules, null, 2)
|
|
427
|
+
}]
|
|
428
|
+
};
|
|
429
|
+
} catch (fetchError) {
|
|
430
|
+
console.error(`[getAIToolRules] Fetch error:`, fetchError);
|
|
431
|
+
throw fetchError;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
case "exportMCPConfig": {
|
|
435
|
+
const tool = args?.tool;
|
|
436
|
+
const serverName = data.meta.name.toLowerCase().replace(/[^a-z0-9]/g, "-");
|
|
437
|
+
const npxArgs = ["@atomixstudio/mcp@latest"];
|
|
438
|
+
if (dsId) npxArgs.push("--ds-id", dsId);
|
|
439
|
+
if (apiKey) npxArgs.push("--api-key", apiKey);
|
|
440
|
+
const config = {
|
|
441
|
+
mcpServers: {
|
|
442
|
+
[serverName]: {
|
|
443
|
+
command: "npx",
|
|
444
|
+
args: npxArgs
|
|
445
|
+
}
|
|
2552
446
|
}
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
return {
|
|
2565
|
-
content: [
|
|
2566
|
-
{
|
|
447
|
+
};
|
|
448
|
+
const configs = {
|
|
449
|
+
cursor: { path: ".cursor/mcp.json", content: JSON.stringify(config, null, 2) },
|
|
450
|
+
"claude-desktop": { path: "claude_desktop_config.json", content: JSON.stringify(config, null, 2) },
|
|
451
|
+
windsurf: { path: ".windsurf/mcp.json", content: JSON.stringify(config, null, 2) },
|
|
452
|
+
continue: { path: ".continue/config.json", content: JSON.stringify({ models: [], mcpServers: [{ name: serverName, command: "npx", args: npxArgs }] }, null, 2) },
|
|
453
|
+
vscode: { path: ".vscode/settings.json", content: JSON.stringify({ "mcp.servers": config.mcpServers }, null, 2) }
|
|
454
|
+
};
|
|
455
|
+
if (tool === "all") {
|
|
456
|
+
return {
|
|
457
|
+
content: [{
|
|
2567
458
|
type: "text",
|
|
2568
459
|
text: JSON.stringify({
|
|
2569
|
-
message:
|
|
2570
|
-
configs:
|
|
2571
|
-
tool:
|
|
2572
|
-
path: c.path,
|
|
2573
|
-
filename: c.filename
|
|
2574
|
-
})),
|
|
2575
|
-
files: allConfigs.map((c) => ({
|
|
2576
|
-
tool: c.tool,
|
|
460
|
+
message: "MCP configurations for all tools",
|
|
461
|
+
configs: Object.entries(configs).map(([t, c]) => ({
|
|
462
|
+
tool: t,
|
|
2577
463
|
path: c.path,
|
|
2578
|
-
content: c.content
|
|
2579
|
-
instructions: c.instructions
|
|
464
|
+
content: JSON.parse(c.content)
|
|
2580
465
|
}))
|
|
2581
466
|
}, null, 2)
|
|
2582
|
-
}
|
|
2583
|
-
|
|
2584
|
-
}
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
content: [
|
|
2590
|
-
{
|
|
467
|
+
}]
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
const selectedConfig = configs[tool];
|
|
471
|
+
if (!selectedConfig) {
|
|
472
|
+
return {
|
|
473
|
+
content: [{
|
|
2591
474
|
type: "text",
|
|
2592
475
|
text: JSON.stringify({
|
|
2593
|
-
tool:
|
|
2594
|
-
|
|
2595
|
-
filename: config.filename,
|
|
2596
|
-
content: config.content,
|
|
2597
|
-
instructions: config.instructions
|
|
476
|
+
error: `Unknown tool: ${tool}`,
|
|
477
|
+
availableTools: Object.keys(configs)
|
|
2598
478
|
}, null, 2)
|
|
2599
|
-
}
|
|
2600
|
-
|
|
2601
|
-
}
|
|
2602
|
-
} catch (error) {
|
|
479
|
+
}]
|
|
480
|
+
};
|
|
481
|
+
}
|
|
2603
482
|
return {
|
|
2604
|
-
content: [
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
}
|
|
2611
|
-
}
|
|
2612
|
-
]
|
|
483
|
+
content: [{
|
|
484
|
+
type: "text",
|
|
485
|
+
text: JSON.stringify({
|
|
486
|
+
tool,
|
|
487
|
+
path: selectedConfig.path,
|
|
488
|
+
content: JSON.parse(selectedConfig.content),
|
|
489
|
+
instructions: `Create the file at ${selectedConfig.path} with the content above, then restart your IDE.`
|
|
490
|
+
}, null, 2)
|
|
491
|
+
}]
|
|
2613
492
|
};
|
|
2614
493
|
}
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
494
|
+
case "getSetupInstructions": {
|
|
495
|
+
const tool = args?.tool;
|
|
496
|
+
const instructions = {
|
|
497
|
+
cursor: `# Cursor MCP Setup
|
|
498
|
+
|
|
499
|
+
1. Create \`.cursor/mcp.json\` in your project root
|
|
500
|
+
2. Add the MCP configuration (use exportMCPConfig to get it)
|
|
501
|
+
3. Restart Cursor IDE
|
|
502
|
+
4. Verify by asking: "What design tokens are available?"`,
|
|
503
|
+
copilot: `# GitHub Copilot Setup
|
|
504
|
+
|
|
505
|
+
1. Create \`.github/copilot-instructions.md\` in your project
|
|
506
|
+
2. Use getAIToolRules({ tool: "copilot" }) to get the content
|
|
507
|
+
3. Enable custom instructions in VS Code settings:
|
|
508
|
+
"github.copilot.chat.codeGeneration.useInstructionFiles": true`,
|
|
509
|
+
windsurf: `# Windsurf Setup
|
|
510
|
+
|
|
511
|
+
1. Create \`.windsurf/mcp.json\` in your project root
|
|
512
|
+
2. Create \`.windsurfrules\` with rules from getAIToolRules
|
|
513
|
+
3. Restart Windsurf Editor`,
|
|
514
|
+
cline: `# Cline Setup
|
|
515
|
+
|
|
516
|
+
1. Create \`.clinerules\` in your project root
|
|
517
|
+
2. Cline auto-detects MCP from .cursor/mcp.json`,
|
|
518
|
+
continue: `# Continue Setup
|
|
519
|
+
|
|
520
|
+
1. Create/edit \`.continue/config.json\`
|
|
521
|
+
2. Add mcpServers configuration
|
|
522
|
+
3. Restart VS Code`,
|
|
523
|
+
zed: `# Zed Setup
|
|
524
|
+
|
|
525
|
+
1. Create \`.zed/assistant/rules.md\` in your project
|
|
526
|
+
2. Use getAIToolRules({ tool: "zed" }) for content`,
|
|
527
|
+
"claude-desktop": `# Claude Desktop Setup
|
|
528
|
+
|
|
529
|
+
1. Find your Claude config:
|
|
530
|
+
- macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
|
|
531
|
+
- Windows: %APPDATA%\\Claude\\claude_desktop_config.json
|
|
532
|
+
2. Add MCP server configuration
|
|
533
|
+
3. Restart Claude Desktop`,
|
|
534
|
+
generic: `# Generic AI Tool Setup
|
|
535
|
+
|
|
536
|
+
1. Create AI_GUIDELINES.md in your project root
|
|
537
|
+
2. Use getAIToolRules({ tool: "generic" }) for content
|
|
538
|
+
3. Reference in your prompts or context`
|
|
2627
539
|
};
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
{
|
|
540
|
+
const instruction = instructions[tool];
|
|
541
|
+
if (!instruction) {
|
|
542
|
+
return {
|
|
543
|
+
content: [{
|
|
2632
544
|
type: "text",
|
|
2633
545
|
text: JSON.stringify({
|
|
2634
|
-
error:
|
|
2635
|
-
availableTools: Object.keys(
|
|
546
|
+
error: `Unknown tool: ${tool}`,
|
|
547
|
+
availableTools: Object.keys(instructions)
|
|
2636
548
|
}, 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;
|
|
549
|
+
}]
|
|
550
|
+
};
|
|
2654
551
|
}
|
|
2655
|
-
return true;
|
|
2656
|
-
}).slice(0, 50).map(([path, value]) => {
|
|
2657
|
-
const metadata = getTokenMetadata(path);
|
|
2658
552
|
return {
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
mutable: metadata.mutable,
|
|
2664
|
-
guidance: metadata.guidance
|
|
553
|
+
content: [{
|
|
554
|
+
type: "text",
|
|
555
|
+
text: instruction
|
|
556
|
+
}]
|
|
2665
557
|
};
|
|
2666
|
-
}
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
return 0;
|
|
2671
|
-
});
|
|
2672
|
-
return {
|
|
2673
|
-
content: [
|
|
2674
|
-
{
|
|
558
|
+
}
|
|
559
|
+
default:
|
|
560
|
+
return {
|
|
561
|
+
content: [{
|
|
2675
562
|
type: "text",
|
|
2676
563
|
text: JSON.stringify({
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
count: matches.length,
|
|
2680
|
-
note: "Semantic tokens are listed first. Use semantic tokens for styling; primitives are for reference only.",
|
|
2681
|
-
matches
|
|
564
|
+
error: `Unknown tool: ${name}`,
|
|
565
|
+
availableTools: ["getToken", "listTokens", "searchTokens", "validateUsage", "getAIToolRules", "exportMCPConfig", "getSetupInstructions"]
|
|
2682
566
|
}, null, 2)
|
|
2683
|
-
}
|
|
2684
|
-
|
|
2685
|
-
};
|
|
567
|
+
}]
|
|
568
|
+
};
|
|
2686
569
|
}
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
}
|
|
570
|
+
} catch (error) {
|
|
571
|
+
return {
|
|
572
|
+
content: [{
|
|
573
|
+
type: "text",
|
|
574
|
+
text: JSON.stringify({
|
|
575
|
+
error: error instanceof Error ? error.message : "Unknown error",
|
|
576
|
+
suggestion: "Make sure --ds-id and --api-key are correct."
|
|
577
|
+
}, null, 2)
|
|
578
|
+
}],
|
|
579
|
+
isError: true
|
|
580
|
+
};
|
|
2696
581
|
}
|
|
2697
582
|
});
|
|
583
|
+
var AI_TOOLS = ["cursor", "copilot", "windsurf", "cline", "continue", "zed", "generic"];
|
|
2698
584
|
server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
585
|
+
const data = await fetchDesignSystem();
|
|
586
|
+
const stats = getTokenStats(data);
|
|
587
|
+
const resources = [
|
|
588
|
+
{
|
|
589
|
+
uri: "atomix://welcome",
|
|
590
|
+
name: `Welcome to ${data.meta.name}`,
|
|
591
|
+
description: `Design system overview with ${stats.total} tokens and ${stats.governanceRules} governance rules`,
|
|
592
|
+
mimeType: "text/markdown"
|
|
593
|
+
},
|
|
594
|
+
...AI_TOOLS.map((tool) => ({
|
|
595
|
+
uri: `atomix://rules/${tool}`,
|
|
596
|
+
name: `${tool.charAt(0).toUpperCase() + tool.slice(1)} Rules`,
|
|
597
|
+
description: `Design system rules file for ${tool}`,
|
|
598
|
+
mimeType: "text/markdown"
|
|
599
|
+
}))
|
|
600
|
+
];
|
|
601
|
+
return { resources };
|
|
602
|
+
});
|
|
603
|
+
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
604
|
+
const { uri } = request.params;
|
|
605
|
+
const data = await fetchDesignSystem();
|
|
606
|
+
const stats = getTokenStats(data);
|
|
607
|
+
if (uri === "atomix://welcome") {
|
|
608
|
+
const welcome = generateWelcomeMessage(data, stats);
|
|
609
|
+
return {
|
|
610
|
+
contents: [{
|
|
611
|
+
uri,
|
|
612
|
+
mimeType: "text/markdown",
|
|
613
|
+
text: welcome
|
|
614
|
+
}]
|
|
615
|
+
};
|
|
616
|
+
}
|
|
617
|
+
const rulesMatch = uri.match(/^atomix:\/\/rules\/(.+)$/);
|
|
618
|
+
if (rulesMatch) {
|
|
619
|
+
const tool = rulesMatch[1];
|
|
620
|
+
if (!AI_TOOLS.includes(tool)) {
|
|
621
|
+
throw new Error(`Unknown tool: ${tool}. Available: ${AI_TOOLS.join(", ")}`);
|
|
622
|
+
}
|
|
623
|
+
const rulesUrl = `${apiBase}/api/ds/${dsId}/rules?format=${tool}`;
|
|
624
|
+
const headers = { "Content-Type": "application/json" };
|
|
625
|
+
if (apiKey) headers["x-api-key"] = apiKey;
|
|
626
|
+
const response = await fetch(rulesUrl, { headers });
|
|
627
|
+
if (!response.ok) {
|
|
628
|
+
throw new Error(`Failed to fetch rules: ${response.status}`);
|
|
629
|
+
}
|
|
630
|
+
const rulesData = await response.json();
|
|
631
|
+
return {
|
|
632
|
+
contents: [{
|
|
633
|
+
uri,
|
|
634
|
+
mimeType: "text/markdown",
|
|
635
|
+
text: rulesData.content || JSON.stringify(rulesData, null, 2)
|
|
636
|
+
}]
|
|
637
|
+
};
|
|
638
|
+
}
|
|
639
|
+
throw new Error(`Unknown resource: ${uri}`);
|
|
640
|
+
});
|
|
641
|
+
server.setRequestHandler(ListPromptsRequestSchema, async () => {
|
|
2699
642
|
return {
|
|
2700
|
-
|
|
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
|
-
},
|
|
643
|
+
prompts: [
|
|
2719
644
|
{
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
description: "Spacing scale, insets, gaps",
|
|
2723
|
-
mimeType: "application/json"
|
|
645
|
+
name: "welcome",
|
|
646
|
+
description: "Get started with this design system - shows overview, available tokens, and tools. Run this first!"
|
|
2724
647
|
},
|
|
2725
648
|
{
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
649
|
+
name: "design-system-rules",
|
|
650
|
+
description: "Get the design system governance rules for your AI coding tool",
|
|
651
|
+
arguments: [
|
|
652
|
+
{
|
|
653
|
+
name: "tool",
|
|
654
|
+
description: "AI tool to generate rules for (cursor, copilot, windsurf, cline, continue, zed, generic)",
|
|
655
|
+
required: false
|
|
656
|
+
}
|
|
657
|
+
]
|
|
2730
658
|
}
|
|
2731
659
|
]
|
|
2732
660
|
};
|
|
2733
661
|
});
|
|
2734
|
-
server.setRequestHandler(
|
|
2735
|
-
const
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
uri,
|
|
2742
|
-
mimeType: "application/json",
|
|
2743
|
-
text: JSON.stringify(primitives2, null, 2)
|
|
2744
|
-
}
|
|
2745
|
-
]
|
|
2746
|
-
};
|
|
2747
|
-
case "atomix://tokens/colors":
|
|
662
|
+
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
663
|
+
const { name, arguments: args } = request.params;
|
|
664
|
+
const data = await fetchDesignSystem();
|
|
665
|
+
const stats = getTokenStats(data);
|
|
666
|
+
switch (name) {
|
|
667
|
+
case "welcome": {
|
|
668
|
+
const welcome = generateWelcomeMessage(data, stats);
|
|
2748
669
|
return {
|
|
2749
|
-
|
|
670
|
+
description: `Welcome to ${data.meta.name} Design System`,
|
|
671
|
+
messages: [
|
|
2750
672
|
{
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
case "atomix://tokens/typography":
|
|
2758
|
-
return {
|
|
2759
|
-
contents: [
|
|
673
|
+
role: "user",
|
|
674
|
+
content: {
|
|
675
|
+
type: "text",
|
|
676
|
+
text: "Show me the design system overview and available tools."
|
|
677
|
+
}
|
|
678
|
+
},
|
|
2760
679
|
{
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
680
|
+
role: "assistant",
|
|
681
|
+
content: {
|
|
682
|
+
type: "text",
|
|
683
|
+
text: welcome
|
|
684
|
+
}
|
|
2764
685
|
}
|
|
2765
686
|
]
|
|
2766
687
|
};
|
|
2767
|
-
|
|
688
|
+
}
|
|
689
|
+
case "design-system-rules": {
|
|
690
|
+
const tool = args?.tool || "cursor";
|
|
691
|
+
const rulesUrl = `${apiBase}/api/ds/${dsId}/rules?format=${tool}`;
|
|
692
|
+
const headers = { "Content-Type": "application/json" };
|
|
693
|
+
if (apiKey) headers["x-api-key"] = apiKey;
|
|
694
|
+
const response = await fetch(rulesUrl, { headers });
|
|
695
|
+
if (!response.ok) {
|
|
696
|
+
throw new Error(`Failed to fetch rules: ${response.status}`);
|
|
697
|
+
}
|
|
698
|
+
const rulesData = await response.json();
|
|
2768
699
|
return {
|
|
2769
|
-
|
|
700
|
+
description: `Design system rules for ${tool}`,
|
|
701
|
+
messages: [
|
|
2770
702
|
{
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
case "atomix://components":
|
|
2778
|
-
return {
|
|
2779
|
-
contents: [
|
|
703
|
+
role: "user",
|
|
704
|
+
content: {
|
|
705
|
+
type: "text",
|
|
706
|
+
text: `Show me the design system rules for ${tool}.`
|
|
707
|
+
}
|
|
708
|
+
},
|
|
2780
709
|
{
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
710
|
+
role: "assistant",
|
|
711
|
+
content: {
|
|
712
|
+
type: "text",
|
|
713
|
+
text: rulesData.content || JSON.stringify(rulesData, null, 2)
|
|
714
|
+
}
|
|
2784
715
|
}
|
|
2785
716
|
]
|
|
2786
717
|
};
|
|
718
|
+
}
|
|
2787
719
|
default:
|
|
2788
|
-
throw new Error(`Unknown
|
|
720
|
+
throw new Error(`Unknown prompt: ${name}`);
|
|
2789
721
|
}
|
|
2790
722
|
});
|
|
2791
|
-
function
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
723
|
+
function generateWelcomeMessage(data, stats) {
|
|
724
|
+
const toolsList = [
|
|
725
|
+
"getToken - Get a specific token by path",
|
|
726
|
+
"listTokens - List all tokens in a category",
|
|
727
|
+
"searchTokens - Search tokens by name or value",
|
|
728
|
+
"validateUsage - Check if a CSS value follows the design system",
|
|
729
|
+
"getAIToolRules - Generate AI coding rules for any tool",
|
|
730
|
+
"exportMCPConfig - Generate MCP config for AI tools",
|
|
731
|
+
"getSetupInstructions - Get setup guide for specific tools"
|
|
732
|
+
];
|
|
733
|
+
const categoryBreakdown = Object.entries(stats.byCategory).map(([cat, count]) => ` - ${cat}: ${count} tokens`).join("\n");
|
|
734
|
+
const asciiArt = `
|
|
735
|
+
\`\`\`
|
|
736
|
+
\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198
|
|
737
|
+
\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198
|
|
738
|
+
\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198
|
|
739
|
+
\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198
|
|
740
|
+
\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198
|
|
741
|
+
\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198
|
|
742
|
+
\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198
|
|
743
|
+
\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198
|
|
744
|
+
\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198
|
|
745
|
+
\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198
|
|
746
|
+
\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198
|
|
747
|
+
\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198 \u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198
|
|
748
|
+
\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198 \u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198
|
|
749
|
+
\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198 \u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198
|
|
750
|
+
\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198 \u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198
|
|
751
|
+
\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198
|
|
752
|
+
\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198
|
|
753
|
+
\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198
|
|
754
|
+
\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198
|
|
755
|
+
\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198
|
|
756
|
+
\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198
|
|
757
|
+
\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198
|
|
758
|
+
\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198
|
|
759
|
+
\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198
|
|
760
|
+
\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198
|
|
761
|
+
\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198\u2198
|
|
762
|
+
\`\`\`
|
|
763
|
+
`;
|
|
764
|
+
return `${asciiArt}
|
|
765
|
+
# Welcome to ${data.meta.name}
|
|
766
|
+
|
|
767
|
+
Your design system is connected and ready to use.
|
|
768
|
+
|
|
769
|
+
## Design System Overview
|
|
770
|
+
|
|
771
|
+
| Metric | Value |
|
|
772
|
+
|--------|-------|
|
|
773
|
+
| Name | ${data.meta.name} |
|
|
774
|
+
| DS ID | ${dsId} |
|
|
775
|
+
| Total Tokens | ${stats.total} |
|
|
776
|
+
| CSS Variables | ${stats.cssVariables} |
|
|
777
|
+
| Governance Rules | ${stats.governanceRules} |
|
|
778
|
+
| Version | ${data.meta.version || 1} |
|
|
779
|
+
|
|
780
|
+
### Token Breakdown
|
|
781
|
+
|
|
782
|
+
${categoryBreakdown}
|
|
783
|
+
|
|
784
|
+
## Available Tools
|
|
785
|
+
|
|
786
|
+
${toolsList.map((t, i) => `${i + 1}. **${t.split(" - ")[0]}** - ${t.split(" - ")[1]}`).join("\n")}
|
|
787
|
+
|
|
788
|
+
## Quick Start
|
|
789
|
+
|
|
790
|
+
### Get a Token
|
|
791
|
+
\`\`\`
|
|
792
|
+
Use getToken with path "colors.static.brand.primary"
|
|
793
|
+
\`\`\`
|
|
794
|
+
|
|
795
|
+
### List All Spacing Tokens
|
|
796
|
+
\`\`\`
|
|
797
|
+
Use listTokens with category "spacing"
|
|
798
|
+
\`\`\`
|
|
799
|
+
|
|
800
|
+
### Validate a Hardcoded Value
|
|
801
|
+
\`\`\`
|
|
802
|
+
Use validateUsage with value "#ff0000" and context "color"
|
|
803
|
+
\`\`\`
|
|
804
|
+
|
|
805
|
+
## Resources Available
|
|
806
|
+
|
|
807
|
+
This MCP server exposes rules files as resources that your AI tool can read:
|
|
808
|
+
|
|
809
|
+
| Resource | Description |
|
|
810
|
+
|----------|-------------|
|
|
811
|
+
| \`atomix://welcome\` | This welcome message |
|
|
812
|
+
| \`atomix://rules/cursor\` | .cursorrules file content |
|
|
813
|
+
| \`atomix://rules/copilot\` | GitHub Copilot instructions |
|
|
814
|
+
| \`atomix://rules/windsurf\` | .windsurfrules file content |
|
|
815
|
+
| \`atomix://rules/cline\` | .clinerules file content |
|
|
816
|
+
| \`atomix://rules/continue\` | Continue rules |
|
|
817
|
+
| \`atomix://rules/zed\` | Zed assistant rules |
|
|
818
|
+
| \`atomix://rules/generic\` | Generic AI guidelines |
|
|
819
|
+
|
|
820
|
+
## Checking for Updates
|
|
821
|
+
|
|
822
|
+
Your design system may be updated over time. To ensure you have the latest tokens:
|
|
823
|
+
|
|
824
|
+
1. **Check version**: The current version is ${data.meta.version || 1}
|
|
825
|
+
2. **Refresh tokens**: Restart the MCP server to fetch latest tokens
|
|
826
|
+
3. **View changes**: Visit https://atomixstudio.eu/ds/${dsId} to see recent changes
|
|
827
|
+
|
|
828
|
+
---
|
|
829
|
+
|
|
830
|
+
*Powered by Atomix Studio - https://atomixstudio.eu*
|
|
831
|
+
`;
|
|
832
|
+
}
|
|
833
|
+
function findConfig() {
|
|
834
|
+
const configNames = [".atomixrc", ".atomixrc.json", "atomix.config.json"];
|
|
835
|
+
const cwd = process.cwd();
|
|
836
|
+
for (const name of configNames) {
|
|
837
|
+
const configPath = path.join(cwd, name);
|
|
838
|
+
if (fs.existsSync(configPath)) {
|
|
839
|
+
try {
|
|
840
|
+
const content = fs.readFileSync(configPath, "utf-8");
|
|
841
|
+
return JSON.parse(content);
|
|
842
|
+
} catch {
|
|
843
|
+
console.error(`Error parsing ${name}`);
|
|
844
|
+
}
|
|
845
|
+
}
|
|
2800
846
|
}
|
|
2801
847
|
return null;
|
|
2802
848
|
}
|
|
2803
|
-
function
|
|
2804
|
-
const
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
849
|
+
function generateCSSOutput(cssVariables) {
|
|
850
|
+
const lines = [
|
|
851
|
+
"/* Atomix Design System Tokens",
|
|
852
|
+
" * Auto-generated - do not edit manually",
|
|
853
|
+
` * Synced: ${(/* @__PURE__ */ new Date()).toISOString()}`,
|
|
854
|
+
" */",
|
|
855
|
+
"",
|
|
856
|
+
":root {"
|
|
857
|
+
];
|
|
858
|
+
for (const [key, value] of Object.entries(cssVariables)) {
|
|
859
|
+
lines.push(` ${key}: ${value};`);
|
|
2813
860
|
}
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
861
|
+
lines.push("}");
|
|
862
|
+
lines.push("");
|
|
863
|
+
return lines.join("\n");
|
|
864
|
+
}
|
|
865
|
+
function generateJSONOutput(tokens) {
|
|
866
|
+
return JSON.stringify(tokens, null, 2);
|
|
867
|
+
}
|
|
868
|
+
function generateTSOutput(tokens) {
|
|
869
|
+
return `// Atomix Design System Tokens
|
|
870
|
+
// Auto-generated - do not edit manually
|
|
871
|
+
// Synced: ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
872
|
+
|
|
873
|
+
export const tokens = ${JSON.stringify(tokens, null, 2)} as const;
|
|
874
|
+
|
|
875
|
+
export type Tokens = typeof tokens;
|
|
876
|
+
`;
|
|
877
|
+
}
|
|
878
|
+
function generateJSOutput(tokens) {
|
|
879
|
+
return `// Atomix Design System Tokens
|
|
880
|
+
// Auto-generated - do not edit manually
|
|
881
|
+
// Synced: ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
882
|
+
|
|
883
|
+
export const tokens = ${JSON.stringify(tokens, null, 2)};
|
|
884
|
+
`;
|
|
885
|
+
}
|
|
886
|
+
function generateSCSSOutput(cssVariables) {
|
|
887
|
+
const lines = [
|
|
888
|
+
"// Atomix Design System Tokens",
|
|
889
|
+
"// Auto-generated - do not edit manually",
|
|
890
|
+
`// Synced: ${(/* @__PURE__ */ new Date()).toISOString()}`,
|
|
891
|
+
"",
|
|
892
|
+
"// CSS Custom Properties (for use in CSS/HTML)",
|
|
893
|
+
":root {"
|
|
894
|
+
];
|
|
895
|
+
for (const [key, value] of Object.entries(cssVariables)) {
|
|
896
|
+
lines.push(` ${key}: ${value};`);
|
|
2819
897
|
}
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
);
|
|
898
|
+
lines.push("}");
|
|
899
|
+
lines.push("");
|
|
900
|
+
lines.push("// SCSS Variables (for use in SCSS)");
|
|
901
|
+
for (const [key, value] of Object.entries(cssVariables)) {
|
|
902
|
+
const scssVar = "$" + key.replace(/^--/, "");
|
|
903
|
+
lines.push(`${scssVar}: ${value};`);
|
|
2827
904
|
}
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
905
|
+
lines.push("");
|
|
906
|
+
return lines.join("\n");
|
|
907
|
+
}
|
|
908
|
+
function generateLessOutput(cssVariables) {
|
|
909
|
+
const lines = [
|
|
910
|
+
"// Atomix Design System Tokens",
|
|
911
|
+
"// Auto-generated - do not edit manually",
|
|
912
|
+
`// Synced: ${(/* @__PURE__ */ new Date()).toISOString()}`,
|
|
913
|
+
"",
|
|
914
|
+
"// CSS Custom Properties (for use in CSS/HTML)",
|
|
915
|
+
":root {"
|
|
916
|
+
];
|
|
917
|
+
for (const [key, value] of Object.entries(cssVariables)) {
|
|
918
|
+
lines.push(` ${key}: ${value};`);
|
|
2833
919
|
}
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
);
|
|
920
|
+
lines.push("}");
|
|
921
|
+
lines.push("");
|
|
922
|
+
lines.push("// Less Variables (for use in Less)");
|
|
923
|
+
for (const [key, value] of Object.entries(cssVariables)) {
|
|
924
|
+
const lessVar = "@" + key.replace(/^--/, "");
|
|
925
|
+
lines.push(`${lessVar}: ${value};`);
|
|
2839
926
|
}
|
|
2840
|
-
|
|
927
|
+
lines.push("");
|
|
928
|
+
return lines.join("\n");
|
|
2841
929
|
}
|
|
2842
|
-
function
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
930
|
+
function toSwiftName(cssVar) {
|
|
931
|
+
return cssVar.replace(/^--atmx-/, "").replace(/-([a-z])/g, (_, c) => c.toUpperCase());
|
|
932
|
+
}
|
|
933
|
+
function toKotlinName(cssVar) {
|
|
934
|
+
const camel = toSwiftName(cssVar);
|
|
935
|
+
return camel.charAt(0).toUpperCase() + camel.slice(1);
|
|
936
|
+
}
|
|
937
|
+
function toDartName(cssVar) {
|
|
938
|
+
return toSwiftName(cssVar);
|
|
939
|
+
}
|
|
940
|
+
function isColorValue(value) {
|
|
941
|
+
return /^#[0-9A-Fa-f]{3,8}$/.test(value) || /^rgb/.test(value) || /^hsl/.test(value);
|
|
942
|
+
}
|
|
943
|
+
function hexToSwiftColor(hex) {
|
|
944
|
+
const clean = hex.replace("#", "");
|
|
945
|
+
if (clean.length === 3) {
|
|
946
|
+
const r = clean[0], g = clean[1], b = clean[2];
|
|
947
|
+
return `Color(hex: 0x${r}${r}${g}${g}${b}${b})`;
|
|
948
|
+
}
|
|
949
|
+
if (clean.length === 6) {
|
|
950
|
+
return `Color(hex: 0x${clean})`;
|
|
951
|
+
}
|
|
952
|
+
if (clean.length === 8) {
|
|
953
|
+
const rgb = clean.substring(0, 6);
|
|
954
|
+
const alpha = parseInt(clean.substring(6, 8), 16) / 255;
|
|
955
|
+
return `Color(hex: 0x${rgb}).opacity(${alpha.toFixed(2)})`;
|
|
956
|
+
}
|
|
957
|
+
return `Color.clear // Could not parse: ${hex}`;
|
|
958
|
+
}
|
|
959
|
+
function hexToKotlinColor(hex) {
|
|
960
|
+
const clean = hex.replace("#", "").toUpperCase();
|
|
961
|
+
if (clean.length === 3) {
|
|
962
|
+
const r = clean[0], g = clean[1], b = clean[2];
|
|
963
|
+
return `Color(0xFF${r}${r}${g}${g}${b}${b})`;
|
|
964
|
+
}
|
|
965
|
+
if (clean.length === 6) {
|
|
966
|
+
return `Color(0xFF${clean})`;
|
|
967
|
+
}
|
|
968
|
+
if (clean.length === 8) {
|
|
969
|
+
const rgb = clean.substring(0, 6);
|
|
970
|
+
const alpha = clean.substring(6, 8);
|
|
971
|
+
return `Color(0x${alpha}${rgb})`;
|
|
972
|
+
}
|
|
973
|
+
return `Color.Transparent // Could not parse: ${hex}`;
|
|
974
|
+
}
|
|
975
|
+
function hexToDartColor(hex) {
|
|
976
|
+
const clean = hex.replace("#", "").toUpperCase();
|
|
977
|
+
if (clean.length === 3) {
|
|
978
|
+
const r = clean[0], g = clean[1], b = clean[2];
|
|
979
|
+
return `Color(0xFF${r}${r}${g}${g}${b}${b})`;
|
|
980
|
+
}
|
|
981
|
+
if (clean.length === 6) {
|
|
982
|
+
return `Color(0xFF${clean})`;
|
|
983
|
+
}
|
|
984
|
+
if (clean.length === 8) {
|
|
985
|
+
const rgb = clean.substring(0, 6);
|
|
986
|
+
const alpha = clean.substring(6, 8);
|
|
987
|
+
return `Color(0x${alpha}${rgb})`;
|
|
988
|
+
}
|
|
989
|
+
return `Colors.transparent // Could not parse: ${hex}`;
|
|
990
|
+
}
|
|
991
|
+
function generateSwiftOutput(cssVariables) {
|
|
992
|
+
const lines = [
|
|
993
|
+
"// Atomix Design System Tokens",
|
|
994
|
+
"// Auto-generated - do not edit manually",
|
|
995
|
+
`// Synced: ${(/* @__PURE__ */ new Date()).toISOString()}`,
|
|
996
|
+
"",
|
|
997
|
+
"import SwiftUI",
|
|
998
|
+
"",
|
|
999
|
+
"// MARK: - Color Extension for Hex",
|
|
1000
|
+
"extension Color {",
|
|
1001
|
+
" init(hex: UInt, alpha: Double = 1.0) {",
|
|
1002
|
+
" self.init(",
|
|
1003
|
+
" .sRGB,",
|
|
1004
|
+
" red: Double((hex >> 16) & 0xFF) / 255.0,",
|
|
1005
|
+
" green: Double((hex >> 8) & 0xFF) / 255.0,",
|
|
1006
|
+
" blue: Double(hex & 0xFF) / 255.0,",
|
|
1007
|
+
" opacity: alpha",
|
|
1008
|
+
" )",
|
|
1009
|
+
" }",
|
|
1010
|
+
"}",
|
|
1011
|
+
"",
|
|
1012
|
+
"// MARK: - Design Tokens",
|
|
1013
|
+
"enum DesignTokens {",
|
|
1014
|
+
"",
|
|
1015
|
+
" // MARK: Colors",
|
|
1016
|
+
" enum Colors {"
|
|
1017
|
+
];
|
|
1018
|
+
const colors = [];
|
|
1019
|
+
const spacing = [];
|
|
1020
|
+
const typography = [];
|
|
1021
|
+
const other = [];
|
|
1022
|
+
for (const [key, value] of Object.entries(cssVariables)) {
|
|
1023
|
+
if (key.includes("-color-")) colors.push([key, value]);
|
|
1024
|
+
else if (key.includes("-spacing-")) spacing.push([key, value]);
|
|
1025
|
+
else if (key.includes("-typography-") || key.includes("-font-")) typography.push([key, value]);
|
|
1026
|
+
else other.push([key, value]);
|
|
1027
|
+
}
|
|
1028
|
+
for (const [key, value] of colors) {
|
|
1029
|
+
const name = toSwiftName(key);
|
|
1030
|
+
if (isColorValue(value)) {
|
|
1031
|
+
lines.push(` static let ${name} = ${hexToSwiftColor(value)}`);
|
|
2860
1032
|
}
|
|
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
1033
|
}
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
1034
|
+
lines.push(" }");
|
|
1035
|
+
lines.push("");
|
|
1036
|
+
lines.push(" // MARK: Spacing");
|
|
1037
|
+
lines.push(" enum Spacing {");
|
|
1038
|
+
for (const [key, value] of spacing) {
|
|
1039
|
+
const name = toSwiftName(key);
|
|
1040
|
+
const numValue = parseFloat(value);
|
|
1041
|
+
if (!isNaN(numValue)) {
|
|
1042
|
+
lines.push(` static let ${name}: CGFloat = ${numValue}`);
|
|
1043
|
+
}
|
|
2873
1044
|
}
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
1045
|
+
lines.push(" }");
|
|
1046
|
+
lines.push("");
|
|
1047
|
+
lines.push(" // MARK: Typography");
|
|
1048
|
+
lines.push(" enum Typography {");
|
|
1049
|
+
for (const [key, value] of typography) {
|
|
1050
|
+
const name = toSwiftName(key);
|
|
1051
|
+
if (key.includes("size")) {
|
|
1052
|
+
const numValue = parseFloat(value);
|
|
1053
|
+
if (!isNaN(numValue)) {
|
|
1054
|
+
lines.push(` static let ${name}: CGFloat = ${numValue}`);
|
|
1055
|
+
}
|
|
1056
|
+
} else if (key.includes("weight")) {
|
|
1057
|
+
lines.push(` static let ${name} = "${value}"`);
|
|
1058
|
+
} else if (key.includes("family")) {
|
|
1059
|
+
lines.push(` static let ${name} = "${value}"`);
|
|
1060
|
+
}
|
|
2880
1061
|
}
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
1062
|
+
lines.push(" }");
|
|
1063
|
+
lines.push("");
|
|
1064
|
+
lines.push(" // MARK: Other");
|
|
1065
|
+
lines.push(" enum Other {");
|
|
1066
|
+
for (const [key, value] of other) {
|
|
1067
|
+
const name = toSwiftName(key);
|
|
1068
|
+
if (isColorValue(value)) {
|
|
1069
|
+
lines.push(` static let ${name} = ${hexToSwiftColor(value)}`);
|
|
1070
|
+
} else {
|
|
1071
|
+
const numValue = parseFloat(value);
|
|
1072
|
+
if (!isNaN(numValue)) {
|
|
1073
|
+
lines.push(` static let ${name}: CGFloat = ${numValue}`);
|
|
1074
|
+
} else {
|
|
1075
|
+
lines.push(` static let ${name} = "${value}"`);
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
2887
1078
|
}
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
1079
|
+
lines.push(" }");
|
|
1080
|
+
lines.push("}");
|
|
1081
|
+
lines.push("");
|
|
1082
|
+
return lines.join("\n");
|
|
1083
|
+
}
|
|
1084
|
+
function generateKotlinOutput(cssVariables) {
|
|
1085
|
+
const lines = [
|
|
1086
|
+
"// Atomix Design System Tokens",
|
|
1087
|
+
"// Auto-generated - do not edit manually",
|
|
1088
|
+
`// Synced: ${(/* @__PURE__ */ new Date()).toISOString()}`,
|
|
1089
|
+
"",
|
|
1090
|
+
"package com.atomix.design",
|
|
1091
|
+
"",
|
|
1092
|
+
"import androidx.compose.ui.graphics.Color",
|
|
1093
|
+
"import androidx.compose.ui.unit.dp",
|
|
1094
|
+
"import androidx.compose.ui.unit.sp",
|
|
1095
|
+
"",
|
|
1096
|
+
"object DesignTokens {",
|
|
1097
|
+
"",
|
|
1098
|
+
" object Colors {"
|
|
1099
|
+
];
|
|
1100
|
+
const colors = [];
|
|
1101
|
+
const spacing = [];
|
|
1102
|
+
const typography = [];
|
|
1103
|
+
const other = [];
|
|
1104
|
+
for (const [key, value] of Object.entries(cssVariables)) {
|
|
1105
|
+
if (key.includes("-color-")) colors.push([key, value]);
|
|
1106
|
+
else if (key.includes("-spacing-")) spacing.push([key, value]);
|
|
1107
|
+
else if (key.includes("-typography-") || key.includes("-font-")) typography.push([key, value]);
|
|
1108
|
+
else other.push([key, value]);
|
|
1109
|
+
}
|
|
1110
|
+
for (const [key, value] of colors) {
|
|
1111
|
+
const name = toKotlinName(key);
|
|
1112
|
+
if (isColorValue(value)) {
|
|
1113
|
+
lines.push(` val ${name} = ${hexToKotlinColor(value)}`);
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
lines.push(" }");
|
|
1117
|
+
lines.push("");
|
|
1118
|
+
lines.push(" object Spacing {");
|
|
1119
|
+
for (const [key, value] of spacing) {
|
|
1120
|
+
const name = toKotlinName(key);
|
|
1121
|
+
const numValue = parseFloat(value);
|
|
1122
|
+
if (!isNaN(numValue)) {
|
|
1123
|
+
lines.push(` val ${name} = ${numValue}.dp`);
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
lines.push(" }");
|
|
1127
|
+
lines.push("");
|
|
1128
|
+
lines.push(" object Typography {");
|
|
1129
|
+
for (const [key, value] of typography) {
|
|
1130
|
+
const name = toKotlinName(key);
|
|
1131
|
+
if (key.includes("size")) {
|
|
1132
|
+
const numValue = parseFloat(value);
|
|
1133
|
+
if (!isNaN(numValue)) {
|
|
1134
|
+
lines.push(` val ${name} = ${numValue}.sp`);
|
|
1135
|
+
}
|
|
1136
|
+
} else {
|
|
1137
|
+
lines.push(` const val ${name} = "${value}"`);
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
lines.push(" }");
|
|
1141
|
+
lines.push("");
|
|
1142
|
+
lines.push(" object Other {");
|
|
1143
|
+
for (const [key, value] of other) {
|
|
1144
|
+
const name = toKotlinName(key);
|
|
1145
|
+
if (isColorValue(value)) {
|
|
1146
|
+
lines.push(` val ${name} = ${hexToKotlinColor(value)}`);
|
|
1147
|
+
} else {
|
|
1148
|
+
const numValue = parseFloat(value);
|
|
1149
|
+
if (!isNaN(numValue)) {
|
|
1150
|
+
lines.push(` val ${name} = ${numValue}.dp`);
|
|
1151
|
+
} else {
|
|
1152
|
+
lines.push(` const val ${name} = "${value}"`);
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
2894
1155
|
}
|
|
2895
|
-
|
|
1156
|
+
lines.push(" }");
|
|
1157
|
+
lines.push("}");
|
|
1158
|
+
lines.push("");
|
|
1159
|
+
return lines.join("\n");
|
|
2896
1160
|
}
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
1161
|
+
function generateDartOutput(cssVariables) {
|
|
1162
|
+
const lines = [
|
|
1163
|
+
"// Atomix Design System Tokens",
|
|
1164
|
+
"// Auto-generated - do not edit manually",
|
|
1165
|
+
`// Synced: ${(/* @__PURE__ */ new Date()).toISOString()}`,
|
|
1166
|
+
"",
|
|
1167
|
+
"import 'package:flutter/material.dart';",
|
|
1168
|
+
"",
|
|
1169
|
+
"class DesignTokens {",
|
|
1170
|
+
" DesignTokens._();",
|
|
1171
|
+
"",
|
|
1172
|
+
" // Colors"
|
|
1173
|
+
];
|
|
1174
|
+
const colors = [];
|
|
1175
|
+
const spacing = [];
|
|
1176
|
+
const typography = [];
|
|
1177
|
+
const other = [];
|
|
1178
|
+
for (const [key, value] of Object.entries(cssVariables)) {
|
|
1179
|
+
if (key.includes("-color-")) colors.push([key, value]);
|
|
1180
|
+
else if (key.includes("-spacing-")) spacing.push([key, value]);
|
|
1181
|
+
else if (key.includes("-typography-") || key.includes("-font-")) typography.push([key, value]);
|
|
1182
|
+
else other.push([key, value]);
|
|
1183
|
+
}
|
|
1184
|
+
for (const [key, value] of colors) {
|
|
1185
|
+
const name = toDartName(key);
|
|
1186
|
+
if (isColorValue(value)) {
|
|
1187
|
+
lines.push(` static const ${name} = ${hexToDartColor(value)};`);
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
lines.push("");
|
|
1191
|
+
lines.push(" // Spacing");
|
|
1192
|
+
for (const [key, value] of spacing) {
|
|
1193
|
+
const name = toDartName(key);
|
|
1194
|
+
const numValue = parseFloat(value);
|
|
1195
|
+
if (!isNaN(numValue)) {
|
|
1196
|
+
lines.push(` static const double ${name} = ${numValue};`);
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
lines.push("");
|
|
1200
|
+
lines.push(" // Typography");
|
|
1201
|
+
for (const [key, value] of typography) {
|
|
1202
|
+
const name = toDartName(key);
|
|
1203
|
+
if (key.includes("size")) {
|
|
1204
|
+
const numValue = parseFloat(value);
|
|
1205
|
+
if (!isNaN(numValue)) {
|
|
1206
|
+
lines.push(` static const double ${name} = ${numValue};`);
|
|
1207
|
+
}
|
|
1208
|
+
} else {
|
|
1209
|
+
lines.push(` static const String ${name} = '${value}';`);
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1212
|
+
lines.push("");
|
|
1213
|
+
lines.push(" // Other");
|
|
1214
|
+
for (const [key, value] of other) {
|
|
1215
|
+
const name = toDartName(key);
|
|
1216
|
+
if (isColorValue(value)) {
|
|
1217
|
+
lines.push(` static const ${name} = ${hexToDartColor(value)};`);
|
|
2916
1218
|
} else {
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
1219
|
+
const numValue = parseFloat(value);
|
|
1220
|
+
if (!isNaN(numValue)) {
|
|
1221
|
+
lines.push(` static const double ${name} = ${numValue};`);
|
|
1222
|
+
} else {
|
|
1223
|
+
lines.push(` static const String ${name} = '${value}';`);
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
lines.push("}");
|
|
1228
|
+
lines.push("");
|
|
1229
|
+
return lines.join("\n");
|
|
1230
|
+
}
|
|
1231
|
+
function diffTokens(oldContent, newCssVars, format) {
|
|
1232
|
+
const added = [];
|
|
1233
|
+
const modified = [];
|
|
1234
|
+
const removed = [];
|
|
1235
|
+
if (format === "css" || format === "scss" || format === "less") {
|
|
1236
|
+
const oldVars = {};
|
|
1237
|
+
const varRegex = /(--[\w-]+):\s*([^;]+);/g;
|
|
1238
|
+
let match;
|
|
1239
|
+
while ((match = varRegex.exec(oldContent)) !== null) {
|
|
1240
|
+
oldVars[match[1]] = match[2].trim();
|
|
1241
|
+
}
|
|
1242
|
+
for (const [key, value] of Object.entries(newCssVars)) {
|
|
1243
|
+
if (!(key in oldVars)) {
|
|
1244
|
+
added.push(key);
|
|
1245
|
+
} else if (oldVars[key] !== value) {
|
|
1246
|
+
modified.push({ key, old: oldVars[key], new: value });
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
for (const key of Object.keys(oldVars)) {
|
|
1250
|
+
if (!(key in newCssVars)) {
|
|
1251
|
+
removed.push(key);
|
|
1252
|
+
}
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
return { added, modified, removed };
|
|
1256
|
+
}
|
|
1257
|
+
async function promptConfirm(message) {
|
|
1258
|
+
const rl = readline.createInterface({
|
|
1259
|
+
input: process.stdin,
|
|
1260
|
+
output: process.stdout
|
|
1261
|
+
});
|
|
1262
|
+
return new Promise((resolve2) => {
|
|
1263
|
+
rl.question(`${message} [Y/n] `, (answer) => {
|
|
1264
|
+
rl.close();
|
|
1265
|
+
const normalized = answer.toLowerCase().trim();
|
|
1266
|
+
resolve2(normalized === "" || normalized === "y" || normalized === "yes");
|
|
1267
|
+
});
|
|
1268
|
+
});
|
|
1269
|
+
}
|
|
1270
|
+
async function runSync() {
|
|
1271
|
+
console.log("");
|
|
1272
|
+
console.log(" \u2198\u2198\u2198 Atomix Token Sync");
|
|
1273
|
+
console.log("");
|
|
1274
|
+
const config = findConfig();
|
|
1275
|
+
const effectiveDsId = cliArgs.dsId || config?.dsId;
|
|
1276
|
+
const effectiveApiKey = cliArgs.apiKey || config?.apiKey;
|
|
1277
|
+
const effectiveApiBase = cliArgs.apiBase || config?.apiBase || "https://atomixstudio.eu";
|
|
1278
|
+
const effectiveOutput = cliArgs.output || config?.output || "./tokens.css";
|
|
1279
|
+
const effectiveFormat = cliArgs.format || config?.format || "css";
|
|
1280
|
+
if (!effectiveDsId) {
|
|
1281
|
+
console.error(" Error: Missing design system ID");
|
|
1282
|
+
console.error("");
|
|
1283
|
+
console.error(" Either:");
|
|
1284
|
+
console.error(" 1. Run: npx atomix sync --ds-id <your-ds-id>");
|
|
1285
|
+
console.error(' 2. Create .atomixrc with { "dsId": "<your-ds-id>" }');
|
|
1286
|
+
console.error(" 3. Run: npx atomix init");
|
|
1287
|
+
console.error("");
|
|
1288
|
+
process.exit(1);
|
|
1289
|
+
}
|
|
1290
|
+
console.log(` Fetching tokens from ${effectiveApiBase}...`);
|
|
1291
|
+
const url = `${effectiveApiBase}/api/ds/${effectiveDsId}/tokens?format=export`;
|
|
1292
|
+
const headers = { "Content-Type": "application/json" };
|
|
1293
|
+
if (effectiveApiKey) headers["x-api-key"] = effectiveApiKey;
|
|
1294
|
+
let data;
|
|
1295
|
+
try {
|
|
1296
|
+
const response = await fetch(url, { headers });
|
|
1297
|
+
if (!response.ok) {
|
|
1298
|
+
const errorText = await response.text();
|
|
1299
|
+
console.error(` Error: Failed to fetch tokens (${response.status})`);
|
|
1300
|
+
console.error(` ${errorText}`);
|
|
1301
|
+
process.exit(1);
|
|
1302
|
+
}
|
|
1303
|
+
data = await response.json();
|
|
1304
|
+
} catch (error) {
|
|
1305
|
+
console.error(` Error: Could not connect to ${effectiveApiBase}`);
|
|
1306
|
+
console.error(` ${error instanceof Error ? error.message : String(error)}`);
|
|
1307
|
+
process.exit(1);
|
|
1308
|
+
}
|
|
1309
|
+
console.log(` Design System: ${data.meta.name} (v${data.meta.version})`);
|
|
1310
|
+
console.log("");
|
|
1311
|
+
let newContent;
|
|
1312
|
+
switch (effectiveFormat) {
|
|
1313
|
+
case "css":
|
|
1314
|
+
newContent = generateCSSOutput(data.cssVariables);
|
|
1315
|
+
break;
|
|
1316
|
+
case "scss":
|
|
1317
|
+
newContent = generateSCSSOutput(data.cssVariables);
|
|
1318
|
+
break;
|
|
1319
|
+
case "less":
|
|
1320
|
+
newContent = generateLessOutput(data.cssVariables);
|
|
1321
|
+
break;
|
|
1322
|
+
case "json":
|
|
1323
|
+
newContent = generateJSONOutput(data.tokens);
|
|
1324
|
+
break;
|
|
1325
|
+
case "js":
|
|
1326
|
+
newContent = generateJSOutput(data.tokens);
|
|
1327
|
+
break;
|
|
1328
|
+
case "ts":
|
|
1329
|
+
newContent = generateTSOutput(data.tokens);
|
|
1330
|
+
break;
|
|
1331
|
+
case "swift":
|
|
1332
|
+
newContent = generateSwiftOutput(data.cssVariables);
|
|
1333
|
+
break;
|
|
1334
|
+
case "kotlin":
|
|
1335
|
+
newContent = generateKotlinOutput(data.cssVariables);
|
|
1336
|
+
break;
|
|
1337
|
+
case "dart":
|
|
1338
|
+
newContent = generateDartOutput(data.cssVariables);
|
|
1339
|
+
break;
|
|
1340
|
+
default:
|
|
1341
|
+
newContent = generateCSSOutput(data.cssVariables);
|
|
1342
|
+
break;
|
|
1343
|
+
}
|
|
1344
|
+
const outputPath = path.resolve(process.cwd(), effectiveOutput);
|
|
1345
|
+
const fileExists = fs.existsSync(outputPath);
|
|
1346
|
+
const supportsDiff = ["css", "scss", "less"].includes(effectiveFormat);
|
|
1347
|
+
if (fileExists && supportsDiff) {
|
|
1348
|
+
const oldContent = fs.readFileSync(outputPath, "utf-8");
|
|
1349
|
+
const diff = diffTokens(oldContent, data.cssVariables, effectiveFormat);
|
|
1350
|
+
const totalChanges = diff.added.length + diff.modified.length + diff.removed.length;
|
|
1351
|
+
if (totalChanges === 0) {
|
|
1352
|
+
console.log(" \u2713 Already up to date!");
|
|
1353
|
+
console.log("");
|
|
1354
|
+
process.exit(0);
|
|
1355
|
+
}
|
|
1356
|
+
console.log(` Changes detected in ${path.basename(effectiveOutput)}:`);
|
|
1357
|
+
console.log("");
|
|
1358
|
+
if (diff.modified.length > 0) {
|
|
1359
|
+
for (const { key, old: oldVal, new: newVal } of diff.modified) {
|
|
1360
|
+
console.log(` ${key}`);
|
|
1361
|
+
console.log(` - ${oldVal}`);
|
|
1362
|
+
console.log(` + ${newVal}`);
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1365
|
+
if (diff.added.length > 0) {
|
|
1366
|
+
console.log(` + ${diff.added.length} new token(s)`);
|
|
1367
|
+
}
|
|
1368
|
+
if (diff.removed.length > 0) {
|
|
1369
|
+
console.log(` - ${diff.removed.length} removed token(s)`);
|
|
1370
|
+
}
|
|
1371
|
+
console.log("");
|
|
1372
|
+
console.log(` Total: ${totalChanges} change(s)`);
|
|
1373
|
+
console.log("");
|
|
1374
|
+
if (!cliArgs.yes) {
|
|
1375
|
+
const confirmed = await promptConfirm(" Apply changes?");
|
|
1376
|
+
if (!confirmed) {
|
|
1377
|
+
console.log(" Cancelled.");
|
|
1378
|
+
process.exit(0);
|
|
2932
1379
|
}
|
|
2933
|
-
|
|
2934
|
-
|
|
1380
|
+
}
|
|
1381
|
+
} else if (!fileExists) {
|
|
1382
|
+
console.log(` Creating ${effectiveOutput}...`);
|
|
1383
|
+
console.log(` ${Object.keys(data.cssVariables).length} tokens`);
|
|
1384
|
+
console.log("");
|
|
1385
|
+
if (!cliArgs.yes) {
|
|
1386
|
+
const confirmed = await promptConfirm(" Create file?");
|
|
1387
|
+
if (!confirmed) {
|
|
1388
|
+
console.log(" Cancelled.");
|
|
1389
|
+
process.exit(0);
|
|
2935
1390
|
}
|
|
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
1391
|
}
|
|
2943
|
-
}
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
1392
|
+
}
|
|
1393
|
+
const outputDir = path.dirname(outputPath);
|
|
1394
|
+
if (!fs.existsSync(outputDir)) {
|
|
1395
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
1396
|
+
}
|
|
1397
|
+
fs.writeFileSync(outputPath, newContent);
|
|
1398
|
+
console.log("");
|
|
1399
|
+
console.log(` \u2713 Updated ${effectiveOutput}`);
|
|
1400
|
+
console.log("");
|
|
1401
|
+
}
|
|
1402
|
+
async function runInit() {
|
|
1403
|
+
console.log("");
|
|
1404
|
+
console.log(" \u2198\u2198\u2198 Atomix Config Setup");
|
|
1405
|
+
console.log("");
|
|
1406
|
+
const rl = readline.createInterface({
|
|
1407
|
+
input: process.stdin,
|
|
1408
|
+
output: process.stdout
|
|
1409
|
+
});
|
|
1410
|
+
const question = (prompt) => new Promise((resolve2) => rl.question(prompt, resolve2));
|
|
1411
|
+
const dsId2 = cliArgs.dsId || await question(" Design System ID: ");
|
|
1412
|
+
const output = await question(" Output file [./tokens.css]: ") || "./tokens.css";
|
|
1413
|
+
const format = await question(" Format (css/json/ts) [css]: ") || "css";
|
|
1414
|
+
rl.close();
|
|
1415
|
+
const config = {
|
|
1416
|
+
dsId: dsId2,
|
|
1417
|
+
output,
|
|
1418
|
+
format
|
|
1419
|
+
};
|
|
1420
|
+
const configPath = path.join(process.cwd(), ".atomixrc");
|
|
1421
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
1422
|
+
console.log("");
|
|
1423
|
+
console.log(` \u2713 Created .atomixrc`);
|
|
1424
|
+
console.log("");
|
|
1425
|
+
console.log(" Now run: npx atomix sync");
|
|
1426
|
+
console.log("");
|
|
1427
|
+
}
|
|
1428
|
+
function showHelp() {
|
|
1429
|
+
console.log(`
|
|
1430
|
+
\u2198\u2198\u2198 Atomix CLI
|
|
1431
|
+
|
|
1432
|
+
COMMANDS
|
|
1433
|
+
sync Sync design tokens to your project
|
|
1434
|
+
init Create .atomixrc config file
|
|
1435
|
+
help Show this help message
|
|
1436
|
+
(none) Start MCP server for AI tools
|
|
1437
|
+
|
|
1438
|
+
SYNC OPTIONS
|
|
1439
|
+
--ds-id Design system ID (or set in .atomixrc)
|
|
1440
|
+
--api-key API key for private design systems
|
|
1441
|
+
--output, -o Output file path [./tokens.css]
|
|
1442
|
+
--format Output format [css]
|
|
1443
|
+
WEB:
|
|
1444
|
+
css - CSS custom properties (:root { --var: value })
|
|
1445
|
+
scss - CSS vars + SCSS variables ($var: value)
|
|
1446
|
+
less - CSS vars + Less variables (@var: value)
|
|
1447
|
+
json - Raw token JSON
|
|
1448
|
+
ts - TypeScript with types
|
|
1449
|
+
js - JavaScript ES module
|
|
1450
|
+
NATIVE:
|
|
1451
|
+
swift - SwiftUI (iOS/macOS)
|
|
1452
|
+
kotlin - Jetpack Compose (Android)
|
|
1453
|
+
dart - Flutter
|
|
1454
|
+
--exclude Glob pattern to exclude (can use multiple times)
|
|
1455
|
+
-y, --yes Auto-confirm changes
|
|
1456
|
+
|
|
1457
|
+
MCP SERVER OPTIONS
|
|
1458
|
+
--ds-id Design system ID (required)
|
|
1459
|
+
--api-key API key for private design systems
|
|
1460
|
+
--api-base API base URL [https://atomixstudio.eu]
|
|
1461
|
+
|
|
1462
|
+
EXAMPLES
|
|
1463
|
+
npx atomix sync
|
|
1464
|
+
npx atomix sync --ds-id abc123 -o ./src/tokens.css
|
|
1465
|
+
npx atomix sync --format scss -o ./src/styles/_tokens.scss
|
|
1466
|
+
npx atomix sync --format ts -o ./src/design-tokens.ts
|
|
1467
|
+
npx atomix sync --format swift -o ./Sources/DesignTokens.swift
|
|
1468
|
+
npx atomix sync --format kotlin -o ./app/src/.../DesignTokens.kt
|
|
1469
|
+
npx atomix sync --format dart -o ./lib/design_tokens.dart
|
|
1470
|
+
npx atomix init
|
|
1471
|
+
npx atomix --ds-id abc123 (start MCP server)
|
|
1472
|
+
|
|
1473
|
+
CONFIG FILE (.atomixrc)
|
|
1474
|
+
{
|
|
1475
|
+
"dsId": "your-design-system-id",
|
|
1476
|
+
"output": "./src/styles/tokens.css",
|
|
1477
|
+
"format": "css",
|
|
1478
|
+
"exclude": ["legacy/**", "vendor/**"]
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
DEFAULT SCANNED FILES
|
|
1482
|
+
*.tsx, *.jsx, *.ts, *.js, *.css, *.scss, *.less, *.vue, *.svelte
|
|
1483
|
+
|
|
1484
|
+
DEFAULT EXCLUDED
|
|
1485
|
+
node_modules/**, dist/**, build/**, .next/**, *.min.*, *.d.ts
|
|
1486
|
+
`);
|
|
1487
|
+
}
|
|
1488
|
+
async function startServer() {
|
|
1489
|
+
if (!dsId) {
|
|
1490
|
+
console.error("Error: Missing --ds-id argument");
|
|
1491
|
+
console.error("Usage: npx atomix --ds-id <id> --api-key <key>");
|
|
1492
|
+
console.error("");
|
|
1493
|
+
console.error("For sync command: npx atomix sync --help");
|
|
1494
|
+
console.error("Get your DS ID from https://atomixstudio.eu/ds/[your-ds-id]");
|
|
1495
|
+
process.exit(1);
|
|
2947
1496
|
}
|
|
2948
1497
|
const transport = new StdioServerTransport();
|
|
2949
1498
|
await server.connect(transport);
|
|
2950
|
-
console.error(
|
|
2951
|
-
|
|
2952
|
-
|
|
1499
|
+
console.error(`Atomix MCP Server started for design system: ${dsId}`);
|
|
1500
|
+
}
|
|
1501
|
+
async function main() {
|
|
1502
|
+
switch (cliArgs.command) {
|
|
1503
|
+
case "sync":
|
|
1504
|
+
await runSync();
|
|
1505
|
+
break;
|
|
1506
|
+
case "init":
|
|
1507
|
+
await runInit();
|
|
1508
|
+
break;
|
|
1509
|
+
case "help":
|
|
1510
|
+
showHelp();
|
|
1511
|
+
break;
|
|
1512
|
+
case "server":
|
|
1513
|
+
default:
|
|
1514
|
+
await startServer();
|
|
1515
|
+
break;
|
|
2953
1516
|
}
|
|
2954
1517
|
}
|
|
2955
1518
|
main().catch((error) => {
|
|
2956
|
-
console.error("
|
|
1519
|
+
console.error("Failed:", error);
|
|
2957
1520
|
process.exit(1);
|
|
2958
1521
|
});
|
|
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
1522
|
//# sourceMappingURL=index.js.map
|