@atomixstudio/mcp 1.0.9 → 1.0.10

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/dist/index.js CHANGED
@@ -11,29 +11,1281 @@ import {
11
11
  ListPromptsRequestSchema,
12
12
  GetPromptRequestSchema
13
13
  } from "@modelcontextprotocol/sdk/types.js";
14
- import {
15
- fetchDesignSystem,
16
- getTokenByPath,
17
- flattenTokens,
18
- searchTokens,
19
- getTokenStats,
20
- compareDesignSystems,
21
- generateCSSOutput,
22
- generateSCSSOutput,
23
- generateLessOutput,
24
- generateJSONOutput,
25
- generateTSOutput,
26
- generateJSOutput,
27
- generateSwiftOutput,
28
- generateKotlinOutput,
29
- generateDartOutput,
30
- diffTokens,
31
- formatSyncResponse,
32
- detectGovernanceChangesByFoundation,
33
- syncRulesFiles
34
- } from "@atomixstudio/sync-core";
35
- import * as path from "path";
14
+
15
+ // node_modules/.pnpm/@atomixstudio+sync-core@file+..+atomix-sync-core/node_modules/@atomixstudio/sync-core/dist/index.js
36
16
  import * as fs from "fs";
17
+ import * as path from "path";
18
+ import * as path3 from "path";
19
+ function generateETag(meta) {
20
+ const ts = meta.updatedAt ?? meta.exportedAt ?? "";
21
+ const hash = `${meta.version}-${ts}`;
22
+ return `"v${hash}"`;
23
+ }
24
+ function compareDesignSystems(cached, fresh) {
25
+ const changes = {
26
+ hasChanges: false,
27
+ versionChanged: false,
28
+ timestampChanged: false,
29
+ addedTokens: [],
30
+ removedTokens: [],
31
+ modifiedTokens: [],
32
+ governanceChanged: false,
33
+ summary: ""
34
+ };
35
+ if (cached.meta.version !== fresh.meta.version) {
36
+ changes.versionChanged = true;
37
+ changes.hasChanges = true;
38
+ }
39
+ if (cached.meta.exportedAt !== fresh.meta.exportedAt) {
40
+ changes.timestampChanged = true;
41
+ changes.hasChanges = true;
42
+ }
43
+ const cachedVars = Object.keys(cached.cssVariables);
44
+ const freshVars = Object.keys(fresh.cssVariables);
45
+ for (const varName of freshVars) {
46
+ if (!(varName in cached.cssVariables)) {
47
+ changes.addedTokens.push(varName);
48
+ changes.hasChanges = true;
49
+ }
50
+ }
51
+ for (const varName of cachedVars) {
52
+ if (!(varName in fresh.cssVariables)) {
53
+ changes.removedTokens.push(varName);
54
+ changes.hasChanges = true;
55
+ }
56
+ }
57
+ for (const varName of cachedVars) {
58
+ if (varName in fresh.cssVariables) {
59
+ const oldValue = cached.cssVariables[varName];
60
+ const newValue = fresh.cssVariables[varName];
61
+ if (oldValue !== newValue) {
62
+ changes.modifiedTokens.push({
63
+ token: varName,
64
+ oldValue,
65
+ newValue
66
+ });
67
+ changes.hasChanges = true;
68
+ }
69
+ }
70
+ }
71
+ const cachedDark = cached.tokens?.colors?.modes;
72
+ const freshDark = fresh.tokens?.colors?.modes;
73
+ const cachedDarkColors = cachedDark?.dark || {};
74
+ const freshDarkColors = freshDark?.dark || {};
75
+ const cachedDarkKeys = Object.keys(cachedDarkColors);
76
+ const freshDarkKeys = Object.keys(freshDarkColors);
77
+ const firstColorVar = cachedVars.find((v) => v.includes("-color-")) || freshVars.find((v) => v.includes("-color-"));
78
+ const prefixMatch = firstColorVar?.match(/^(--[a-z]+-color-)/);
79
+ const colorPrefix = prefixMatch ? prefixMatch[1] : "--atmx-color-";
80
+ for (const key of freshDarkKeys) {
81
+ if (!(key in cachedDarkColors)) {
82
+ const cssVarName = `${colorPrefix}${key}`;
83
+ if (!changes.addedTokens.includes(cssVarName)) {
84
+ changes.addedTokens.push(cssVarName);
85
+ changes.hasChanges = true;
86
+ }
87
+ }
88
+ }
89
+ for (const key of cachedDarkKeys) {
90
+ if (!(key in freshDarkColors)) {
91
+ const cssVarName = `${colorPrefix}${key}`;
92
+ if (!changes.removedTokens.includes(cssVarName)) {
93
+ changes.removedTokens.push(cssVarName);
94
+ changes.hasChanges = true;
95
+ }
96
+ }
97
+ }
98
+ for (const key of cachedDarkKeys) {
99
+ if (key in freshDarkColors) {
100
+ const oldValue = cachedDarkColors[key];
101
+ const newValue = freshDarkColors[key];
102
+ if (oldValue !== newValue) {
103
+ const cssVarName = `${colorPrefix}${key}`;
104
+ const existingIndex = changes.modifiedTokens.findIndex((m) => m.token === cssVarName);
105
+ if (existingIndex >= 0) {
106
+ changes.modifiedTokens[existingIndex].oldValue += ` | dark: ${oldValue}`;
107
+ changes.modifiedTokens[existingIndex].newValue += ` | dark: ${newValue}`;
108
+ } else {
109
+ changes.modifiedTokens.push({
110
+ token: `${cssVarName} (dark mode)`,
111
+ oldValue,
112
+ newValue
113
+ });
114
+ changes.hasChanges = true;
115
+ }
116
+ }
117
+ }
118
+ }
119
+ const cachedGovernance = cached.governance || { rules: [], categories: {} };
120
+ const freshGovernance = fresh.governance || { rules: [], categories: {} };
121
+ const cachedRules = cachedGovernance.rules || [];
122
+ const freshRules = freshGovernance.rules || [];
123
+ const cachedCategories = cachedGovernance.categories || {};
124
+ const freshCategories = freshGovernance.categories || {};
125
+ const cachedRulesStr = JSON.stringify(cachedRules.sort());
126
+ const freshRulesStr = JSON.stringify(freshRules.sort());
127
+ const cachedCategoriesStr = JSON.stringify(cachedCategories, Object.keys(cachedCategories).sort());
128
+ const freshCategoriesStr = JSON.stringify(freshCategories, Object.keys(freshCategories).sort());
129
+ if (cachedRulesStr !== freshRulesStr || cachedCategoriesStr !== freshCategoriesStr) {
130
+ changes.governanceChanged = true;
131
+ changes.hasChanges = true;
132
+ }
133
+ const summaryLines = [];
134
+ if (!changes.hasChanges) {
135
+ summaryLines.push("\u2713 No changes detected - design system is up to date");
136
+ } else {
137
+ summaryLines.push("\u{1F4E6} Design System Changes Detected:");
138
+ summaryLines.push("");
139
+ if (changes.versionChanged) {
140
+ summaryLines.push(` Version: ${cached.meta.version} \u2192 ${fresh.meta.version}`);
141
+ }
142
+ if (changes.timestampChanged) {
143
+ const cachedDate = new Date(cached.meta.exportedAt).toLocaleString();
144
+ const freshDate = new Date(fresh.meta.exportedAt).toLocaleString();
145
+ summaryLines.push(` Published: ${cachedDate} \u2192 ${freshDate}`);
146
+ }
147
+ if (changes.addedTokens.length > 0) {
148
+ summaryLines.push(` \u2795 Added: ${changes.addedTokens.length} token(s)`);
149
+ if (changes.addedTokens.length <= 10) {
150
+ changes.addedTokens.forEach((token) => {
151
+ summaryLines.push(` - ${token}`);
152
+ });
153
+ } else {
154
+ changes.addedTokens.slice(0, 10).forEach((token) => {
155
+ summaryLines.push(` - ${token}`);
156
+ });
157
+ summaryLines.push(` ... and ${changes.addedTokens.length - 10} more`);
158
+ }
159
+ }
160
+ if (changes.removedTokens.length > 0) {
161
+ summaryLines.push(` \u2796 Removed: ${changes.removedTokens.length} token(s)`);
162
+ if (changes.removedTokens.length <= 10) {
163
+ changes.removedTokens.forEach((token) => {
164
+ summaryLines.push(` - ${token}`);
165
+ });
166
+ } else {
167
+ changes.removedTokens.slice(0, 10).forEach((token) => {
168
+ summaryLines.push(` - ${token}`);
169
+ });
170
+ summaryLines.push(` ... and ${changes.removedTokens.length - 10} more`);
171
+ }
172
+ }
173
+ if (changes.modifiedTokens.length > 0) {
174
+ summaryLines.push(` \u{1F504} Modified: ${changes.modifiedTokens.length} token(s)`);
175
+ if (changes.modifiedTokens.length <= 10) {
176
+ changes.modifiedTokens.forEach(({ token, oldValue, newValue }) => {
177
+ summaryLines.push(` ${token}:`);
178
+ summaryLines.push(` - ${oldValue}`);
179
+ summaryLines.push(` + ${newValue}`);
180
+ });
181
+ } else {
182
+ changes.modifiedTokens.slice(0, 5).forEach(({ token, oldValue, newValue }) => {
183
+ summaryLines.push(` ${token}:`);
184
+ summaryLines.push(` - ${oldValue}`);
185
+ summaryLines.push(` + ${newValue}`);
186
+ });
187
+ summaryLines.push(` ... and ${changes.modifiedTokens.length - 5} more`);
188
+ }
189
+ }
190
+ if (changes.governanceChanged) {
191
+ summaryLines.push(` \u{1F4DD} AI guide updated`);
192
+ }
193
+ }
194
+ changes.summary = summaryLines.join("\n");
195
+ return changes;
196
+ }
197
+ function detectGovernanceChangesByFoundation(cached, fresh) {
198
+ const changes = [];
199
+ const cachedGov = cached.governance || { rules: [], categories: {} };
200
+ const freshGov = fresh.governance || { rules: [], categories: {} };
201
+ const cachedRulesStr = JSON.stringify((cachedGov.rules || []).sort());
202
+ const freshRulesStr = JSON.stringify((freshGov.rules || []).sort());
203
+ if (cachedRulesStr !== freshRulesStr) {
204
+ changes.push("general");
205
+ }
206
+ const cachedCategories = cachedGov.categories || {};
207
+ const freshCategories = freshGov.categories || {};
208
+ const allFoundationKeys = /* @__PURE__ */ new Set([
209
+ ...Object.keys(cachedCategories),
210
+ ...Object.keys(freshCategories)
211
+ ]);
212
+ for (const foundation of allFoundationKeys) {
213
+ const cachedRules = cachedCategories[foundation] || [];
214
+ const freshRules = freshCategories[foundation] || [];
215
+ const cachedRulesStr2 = JSON.stringify(cachedRules.sort());
216
+ const freshRulesStr2 = JSON.stringify(freshRules.sort());
217
+ if (cachedRulesStr2 !== freshRulesStr2) {
218
+ changes.push(foundation);
219
+ }
220
+ }
221
+ return changes;
222
+ }
223
+ async function fetchDesignSystem(options) {
224
+ const { dsId: dsId2, apiKey: apiKey2, apiBase: apiBase2 = "https://atomixstudio.eu", etag, forceRefresh = false } = options;
225
+ if (!dsId2) {
226
+ throw new Error("Missing dsId. Usage: fetchDesignSystem({ dsId: '...' })");
227
+ }
228
+ const url = `${apiBase2}/api/ds/${dsId2}/tokens?format=export`;
229
+ const headers = {
230
+ "Content-Type": "application/json"
231
+ };
232
+ if (apiKey2) {
233
+ headers["x-api-key"] = apiKey2;
234
+ }
235
+ if (etag) {
236
+ headers["if-none-match"] = etag;
237
+ }
238
+ const response = await fetch(url, { headers });
239
+ if (response.status === 304) {
240
+ return {
241
+ data: null,
242
+ etag,
243
+ status: 304
244
+ };
245
+ }
246
+ if (!response.ok) {
247
+ const text = await response.text();
248
+ throw new Error(`Failed to fetch design system: ${response.status} ${text}`);
249
+ }
250
+ const data = await response.json();
251
+ const responseETag = response.headers.get("etag");
252
+ const finalETag = responseETag || generateETag(data.meta);
253
+ const designSystemData = {
254
+ tokens: data.tokens,
255
+ cssVariables: data.cssVariables,
256
+ governance: data.governance,
257
+ meta: data.meta
258
+ };
259
+ return {
260
+ data: designSystemData,
261
+ etag: finalETag,
262
+ status: 200
263
+ };
264
+ }
265
+ function diffTokens(oldContent, newCssVars, format, newDarkVars) {
266
+ const added = [];
267
+ const modified = [];
268
+ const removed = [];
269
+ const addedDark = [];
270
+ const modifiedDark = [];
271
+ const removedDark = [];
272
+ if (format === "css" || format === "scss" || format === "less") {
273
+ const rootMatch = oldContent.match(/:root\s*\{([^}]*)\}/);
274
+ const darkMatch = oldContent.match(/\.dark[^{]*\{([^}]*)\}/);
275
+ const oldLightVars = {};
276
+ if (rootMatch) {
277
+ const rootContent = rootMatch[1];
278
+ const varRegex = /(--[\w-]+):\s*([^;]+);/g;
279
+ let match;
280
+ while ((match = varRegex.exec(rootContent)) !== null) {
281
+ oldLightVars[match[1]] = match[2].trim();
282
+ }
283
+ } else {
284
+ const varRegex = /(--[\w-]+):\s*([^;]+);/g;
285
+ let match;
286
+ while ((match = varRegex.exec(oldContent)) !== null) {
287
+ if (!(match[1] in oldLightVars)) {
288
+ oldLightVars[match[1]] = match[2].trim();
289
+ }
290
+ }
291
+ }
292
+ const oldDarkVars = {};
293
+ if (darkMatch) {
294
+ const darkContent = darkMatch[1];
295
+ const varRegex = /(--[\w-]+):\s*([^;]+);/g;
296
+ let match;
297
+ while ((match = varRegex.exec(darkContent)) !== null) {
298
+ oldDarkVars[match[1]] = match[2].trim();
299
+ }
300
+ }
301
+ for (const [key, value] of Object.entries(newCssVars)) {
302
+ if (!(key in oldLightVars)) {
303
+ added.push(key);
304
+ } else if (oldLightVars[key] !== value) {
305
+ modified.push({ key, old: oldLightVars[key], new: value });
306
+ }
307
+ }
308
+ for (const key of Object.keys(oldLightVars)) {
309
+ if (!(key in newCssVars)) {
310
+ removed.push(key);
311
+ }
312
+ }
313
+ if (newDarkVars && Object.keys(newDarkVars).length > 0) {
314
+ const firstKey = Object.keys(newCssVars)[0] || "--atmx-";
315
+ const prefixMatch = firstKey.match(/^(--[a-z]+-)/);
316
+ const prefix = prefixMatch ? prefixMatch[1] : "--atmx-";
317
+ for (const [key, value] of Object.entries(newDarkVars)) {
318
+ const cssVarName = `${prefix}color-${key}`;
319
+ if (!(cssVarName in oldDarkVars)) {
320
+ addedDark.push(cssVarName);
321
+ } else if (oldDarkVars[cssVarName] !== value) {
322
+ modifiedDark.push({ key: cssVarName, old: oldDarkVars[cssVarName], new: value });
323
+ }
324
+ }
325
+ for (const key of Object.keys(oldDarkVars)) {
326
+ const shortKey = key.replace(new RegExp(`^${prefix}color-`), "");
327
+ if (!(shortKey in newDarkVars)) {
328
+ removedDark.push(key);
329
+ }
330
+ }
331
+ }
332
+ }
333
+ return { added, modified, removed, addedDark, modifiedDark, removedDark };
334
+ }
335
+ async function syncRulesFiles(options) {
336
+ const { dsId: dsId2, apiKey: apiKey2, apiBase: apiBase2 = "https://atomixstudio.eu", rulesDir = process.cwd() } = options;
337
+ const rulesDirResolved = path.resolve(process.cwd(), rulesDir);
338
+ const toolsToSync = [
339
+ { tool: "cursor", filename: ".cursorrules" },
340
+ { tool: "windsurf", filename: ".windsurfrules" },
341
+ { tool: "cline", filename: ".clinerules" },
342
+ { tool: "continue", filename: ".continuerules" },
343
+ { tool: "copilot", filename: "copilot-instructions.md", dir: ".github" },
344
+ { tool: "generic", filename: "AI_GUIDELINES.md" }
345
+ ];
346
+ const existingTools = toolsToSync.filter((t) => {
347
+ const filePath = t.dir ? path.join(rulesDirResolved, t.dir, t.filename) : path.join(rulesDirResolved, t.filename);
348
+ return fs.existsSync(filePath);
349
+ });
350
+ const toolsToWrite = existingTools.length > 0 ? existingTools : [{ tool: "cursor", filename: ".cursorrules" }];
351
+ const results = [];
352
+ for (const { tool, filename, dir } of toolsToWrite) {
353
+ try {
354
+ const rulesUrl = `${apiBase2}/api/ds/${dsId2}/rules?format=${tool}`;
355
+ const headers = { "Content-Type": "application/json" };
356
+ if (apiKey2) headers["x-api-key"] = apiKey2;
357
+ const response = await fetch(rulesUrl, { headers });
358
+ if (!response.ok) {
359
+ results.push({
360
+ tool,
361
+ filename,
362
+ path: dir ? `${dir}/${filename}` : filename,
363
+ success: false,
364
+ error: `Failed to fetch ${tool} rules: ${response.status}`
365
+ });
366
+ continue;
367
+ }
368
+ const rulesData = await response.json();
369
+ if (!rulesData.content) {
370
+ results.push({
371
+ tool,
372
+ filename,
373
+ path: dir ? `${dir}/${filename}` : filename,
374
+ success: false,
375
+ error: `No content for ${tool} rules`
376
+ });
377
+ continue;
378
+ }
379
+ const targetDir = dir ? path.join(rulesDirResolved, dir) : rulesDirResolved;
380
+ if (!fs.existsSync(targetDir)) {
381
+ fs.mkdirSync(targetDir, { recursive: true });
382
+ }
383
+ const filePath = path.join(targetDir, filename);
384
+ fs.writeFileSync(filePath, rulesData.content);
385
+ results.push({
386
+ tool,
387
+ filename,
388
+ path: dir ? `${dir}/${filename}` : filename,
389
+ success: true
390
+ });
391
+ } catch (error) {
392
+ results.push({
393
+ tool,
394
+ filename,
395
+ path: dir ? `${dir}/${filename}` : filename,
396
+ success: false,
397
+ error: error instanceof Error ? error.message : String(error)
398
+ });
399
+ }
400
+ }
401
+ return results;
402
+ }
403
+ function generateCSSOutput(cssVariables, darkModeColors, deprecatedTokens = /* @__PURE__ */ new Map()) {
404
+ const lines = [
405
+ "/* Atomix Design System Tokens",
406
+ " * Auto-generated - do not edit manually",
407
+ ` * Synced: ${(/* @__PURE__ */ new Date()).toISOString()}`,
408
+ " *",
409
+ " * WARNING: This file is completely rewritten on each sync.",
410
+ " * Only CSS custom properties (variables) are preserved.",
411
+ " * Custom CSS rules (selectors, classes, etc.) will be lost.",
412
+ " * Keep custom CSS in a separate file.",
413
+ " */",
414
+ "",
415
+ "/* Light mode (default) */",
416
+ ":root {"
417
+ ];
418
+ const allVars = /* @__PURE__ */ new Map();
419
+ for (const [key, value] of Object.entries(cssVariables)) {
420
+ allVars.set(key, { value, deprecated: false });
421
+ }
422
+ for (const [key, value] of deprecatedTokens.entries()) {
423
+ allVars.set(key, { value, deprecated: true });
424
+ }
425
+ const sortedKeys = Array.from(allVars.keys()).sort();
426
+ for (const key of sortedKeys) {
427
+ const { value, deprecated } = allVars.get(key);
428
+ if (deprecated) {
429
+ lines.push(` /* DEPRECATED */ ${key}: ${value};`);
430
+ } else {
431
+ lines.push(` ${key}: ${value};`);
432
+ }
433
+ }
434
+ lines.push("}");
435
+ if (darkModeColors && Object.keys(darkModeColors).length > 0) {
436
+ lines.push("");
437
+ lines.push("/* Dark mode */");
438
+ lines.push(".dark,");
439
+ lines.push('[data-theme="dark"] {');
440
+ const firstKey = sortedKeys[0] || "--atmx-";
441
+ const prefixMatch = firstKey.match(/^(--[a-z]+-)/);
442
+ const prefix = prefixMatch ? prefixMatch[1] : "--atmx-";
443
+ const sortedDarkKeys = Object.keys(darkModeColors).sort();
444
+ for (const key of sortedDarkKeys) {
445
+ lines.push(` ${prefix}color-${key}: ${darkModeColors[key]};`);
446
+ }
447
+ lines.push("}");
448
+ }
449
+ lines.push("");
450
+ return lines.join("\n");
451
+ }
452
+ function generateSCSSOutput(cssVariables, darkModeColors, deprecatedTokens = /* @__PURE__ */ new Map()) {
453
+ const lines = [
454
+ "// Atomix Design System Tokens",
455
+ "// Auto-generated - do not edit manually",
456
+ `// Synced: ${(/* @__PURE__ */ new Date()).toISOString()}`,
457
+ "",
458
+ "// CSS Custom Properties (for use in CSS/HTML)",
459
+ "// Light mode (default)",
460
+ ":root {"
461
+ ];
462
+ const allVars = /* @__PURE__ */ new Map();
463
+ for (const [key, value] of Object.entries(cssVariables)) {
464
+ allVars.set(key, { value, deprecated: false });
465
+ }
466
+ for (const [key, value] of deprecatedTokens.entries()) {
467
+ allVars.set(key, { value, deprecated: true });
468
+ }
469
+ const sortedKeys = Array.from(allVars.keys()).sort();
470
+ for (const key of sortedKeys) {
471
+ const { value, deprecated } = allVars.get(key);
472
+ if (deprecated) {
473
+ lines.push(` // DEPRECATED ${key}: ${value};`);
474
+ } else {
475
+ lines.push(` ${key}: ${value};`);
476
+ }
477
+ }
478
+ lines.push("}");
479
+ if (darkModeColors && Object.keys(darkModeColors).length > 0) {
480
+ lines.push("");
481
+ lines.push("// Dark mode");
482
+ lines.push(".dark,");
483
+ lines.push('[data-theme="dark"] {');
484
+ const firstKey = sortedKeys[0] || "--atmx-";
485
+ const prefixMatch = firstKey.match(/^(--[a-z]+-)/);
486
+ const prefix = prefixMatch ? prefixMatch[1] : "--atmx-";
487
+ for (const [key, value] of Object.entries(darkModeColors)) {
488
+ lines.push(` ${prefix}color-${key}: ${value};`);
489
+ }
490
+ lines.push("}");
491
+ }
492
+ lines.push("");
493
+ lines.push("// SCSS Variables (light mode values)");
494
+ for (const key of sortedKeys) {
495
+ const { value, deprecated } = allVars.get(key);
496
+ const scssVar = "$" + key.replace(/^--/, "");
497
+ if (deprecated) {
498
+ lines.push(`// DEPRECATED ${scssVar}: ${value};`);
499
+ } else {
500
+ lines.push(`${scssVar}: ${value};`);
501
+ }
502
+ }
503
+ if (darkModeColors && Object.keys(darkModeColors).length > 0) {
504
+ lines.push("");
505
+ lines.push("// SCSS Variables (dark mode values)");
506
+ const firstKey = Object.keys(cssVariables)[0] || "--atmx-";
507
+ const prefixMatch = firstKey.match(/^--([a-z]+)-/);
508
+ const prefix = prefixMatch ? prefixMatch[1] : "atmx";
509
+ for (const [key, value] of Object.entries(darkModeColors)) {
510
+ const scssVar = `$${prefix}-color-${key}-dark`;
511
+ lines.push(`${scssVar}: ${value};`);
512
+ }
513
+ }
514
+ lines.push("");
515
+ return lines.join("\n");
516
+ }
517
+ function generateLessOutput(cssVariables, darkModeColors, deprecatedTokens = /* @__PURE__ */ new Map()) {
518
+ const lines = [
519
+ "// Atomix Design System Tokens",
520
+ "// Auto-generated - do not edit manually",
521
+ `// Synced: ${(/* @__PURE__ */ new Date()).toISOString()}`,
522
+ "",
523
+ "// CSS Custom Properties (for use in CSS/HTML)",
524
+ "// Light mode (default)",
525
+ ":root {"
526
+ ];
527
+ const allVars = /* @__PURE__ */ new Map();
528
+ for (const [key, value] of Object.entries(cssVariables)) {
529
+ allVars.set(key, { value, deprecated: false });
530
+ }
531
+ for (const [key, value] of deprecatedTokens.entries()) {
532
+ allVars.set(key, { value, deprecated: true });
533
+ }
534
+ const sortedKeys = Array.from(allVars.keys()).sort();
535
+ for (const key of sortedKeys) {
536
+ const { value, deprecated } = allVars.get(key);
537
+ if (deprecated) {
538
+ lines.push(` // DEPRECATED ${key}: ${value};`);
539
+ } else {
540
+ lines.push(` ${key}: ${value};`);
541
+ }
542
+ }
543
+ lines.push("}");
544
+ if (darkModeColors && Object.keys(darkModeColors).length > 0) {
545
+ lines.push("");
546
+ lines.push("// Dark mode");
547
+ lines.push(".dark,");
548
+ lines.push('[data-theme="dark"] {');
549
+ const firstKey = Object.keys(cssVariables)[0] || "--atmx-";
550
+ const prefixMatch = firstKey.match(/^(--[a-z]+-)/);
551
+ const prefix = prefixMatch ? prefixMatch[1] : "--atmx-";
552
+ for (const [key, value] of Object.entries(darkModeColors)) {
553
+ lines.push(` ${prefix}color-${key}: ${value};`);
554
+ }
555
+ lines.push("}");
556
+ }
557
+ lines.push("");
558
+ lines.push("// Less Variables (light mode values)");
559
+ for (const [key, value] of Object.entries(cssVariables)) {
560
+ const lessVar = "@" + key.replace(/^--/, "");
561
+ lines.push(`${lessVar}: ${value};`);
562
+ }
563
+ if (darkModeColors && Object.keys(darkModeColors).length > 0) {
564
+ lines.push("");
565
+ lines.push("// Less Variables (dark mode values)");
566
+ const firstKey = Object.keys(cssVariables)[0] || "--atmx-";
567
+ const prefixMatch = firstKey.match(/^--([a-z]+)-/);
568
+ const prefix = prefixMatch ? prefixMatch[1] : "atmx";
569
+ for (const [key, value] of Object.entries(darkModeColors)) {
570
+ const lessVar = `@${prefix}-color-${key}-dark`;
571
+ lines.push(`${lessVar}: ${value};`);
572
+ }
573
+ }
574
+ lines.push("");
575
+ return lines.join("\n");
576
+ }
577
+ function generateJSONOutput(tokens) {
578
+ return JSON.stringify(tokens, null, 2);
579
+ }
580
+ function generateTSOutput(tokens) {
581
+ return `// Atomix Design System Tokens
582
+ // Auto-generated - do not edit manually
583
+ // Synced: ${(/* @__PURE__ */ new Date()).toISOString()}
584
+
585
+ export const tokens = ${JSON.stringify(tokens, null, 2)} as const;
586
+
587
+ export type Tokens = typeof tokens;
588
+ `;
589
+ }
590
+ function generateJSOutput(tokens) {
591
+ return `// Atomix Design System Tokens
592
+ // Auto-generated - do not edit manually
593
+ // Synced: ${(/* @__PURE__ */ new Date()).toISOString()}
594
+
595
+ export const tokens = ${JSON.stringify(tokens, null, 2)};
596
+ `;
597
+ }
598
+ function toSwiftName(cssVar) {
599
+ return cssVar.replace(/^--atmx-/, "").replace(/-([a-z])/g, (_, c) => c.toUpperCase());
600
+ }
601
+ function isColorValue(value) {
602
+ return /^#[0-9A-Fa-f]{3,8}$/.test(value) || /^rgb/.test(value) || /^hsl/.test(value);
603
+ }
604
+ function hexToSwiftColor(hex) {
605
+ const clean = hex.replace("#", "");
606
+ if (clean.length === 3) {
607
+ const r = clean[0], g = clean[1], b = clean[2];
608
+ return `Color(hex: 0x${r}${r}${g}${g}${b}${b})`;
609
+ }
610
+ if (clean.length === 6) {
611
+ return `Color(hex: 0x${clean})`;
612
+ }
613
+ if (clean.length === 8) {
614
+ const rgb = clean.substring(0, 6);
615
+ const alpha = parseInt(clean.substring(6, 8), 16) / 255;
616
+ return `Color(hex: 0x${rgb}).opacity(${alpha.toFixed(2)})`;
617
+ }
618
+ return `Color.clear // Could not parse: ${hex}`;
619
+ }
620
+ function generateSwiftOutput(cssVariables, darkModeColors, deprecatedTokens = /* @__PURE__ */ new Map()) {
621
+ const lines = [
622
+ "// Atomix Design System Tokens",
623
+ "// Auto-generated - do not edit manually",
624
+ `// Synced: ${(/* @__PURE__ */ new Date()).toISOString()}`,
625
+ "",
626
+ "import SwiftUI",
627
+ "",
628
+ "// MARK: - Color Extension for Hex",
629
+ "extension Color {",
630
+ " init(hex: UInt, alpha: Double = 1.0) {",
631
+ " self.init(",
632
+ " .sRGB,",
633
+ " red: Double((hex >> 16) & 0xFF) / 255.0,",
634
+ " green: Double((hex >> 8) & 0xFF) / 255.0,",
635
+ " blue: Double(hex & 0xFF) / 255.0,",
636
+ " opacity: alpha",
637
+ " )",
638
+ " }",
639
+ "}",
640
+ "",
641
+ "// MARK: - Design Tokens",
642
+ "enum DesignTokens {",
643
+ "",
644
+ " // MARK: Colors (Light Mode)",
645
+ " enum Colors {"
646
+ ];
647
+ const colors = [];
648
+ const spacing = [];
649
+ const typography = [];
650
+ const other = [];
651
+ for (const [key, value] of Object.entries(cssVariables)) {
652
+ const isDeprecated = false;
653
+ if (key.includes("-color-")) colors.push([key, value, isDeprecated]);
654
+ else if (key.includes("-spacing-")) spacing.push([key, value, isDeprecated]);
655
+ else if (key.includes("-typography-") || key.includes("-font-")) typography.push([key, value, isDeprecated]);
656
+ else other.push([key, value, isDeprecated]);
657
+ }
658
+ for (const [key, value] of deprecatedTokens.entries()) {
659
+ const isDeprecated = true;
660
+ if (key.includes("-color-")) colors.push([key, value, isDeprecated]);
661
+ else if (key.includes("-spacing-")) spacing.push([key, value, isDeprecated]);
662
+ else if (key.includes("-typography-") || key.includes("-font-")) typography.push([key, value, isDeprecated]);
663
+ else other.push([key, value, isDeprecated]);
664
+ }
665
+ colors.sort((a, b) => a[0].localeCompare(b[0]));
666
+ spacing.sort((a, b) => a[0].localeCompare(b[0]));
667
+ typography.sort((a, b) => a[0].localeCompare(b[0]));
668
+ other.sort((a, b) => a[0].localeCompare(b[0]));
669
+ for (const [key, value, isDeprecated] of colors) {
670
+ const name = toSwiftName(key);
671
+ if (isColorValue(value)) {
672
+ if (isDeprecated) {
673
+ lines.push(` @available(*, deprecated, message: "This token has been removed from the design system")`);
674
+ lines.push(` static let ${name} = ${hexToSwiftColor(value)}`);
675
+ } else {
676
+ lines.push(` static let ${name} = ${hexToSwiftColor(value)}`);
677
+ }
678
+ }
679
+ }
680
+ lines.push(" }");
681
+ if (darkModeColors && Object.keys(darkModeColors).length > 0) {
682
+ lines.push("");
683
+ lines.push(" // MARK: Colors (Dark Mode)");
684
+ lines.push(" enum ColorsDark {");
685
+ for (const [key, value] of Object.entries(darkModeColors)) {
686
+ const name = `color${key.split("-").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join("")}`;
687
+ if (isColorValue(value)) {
688
+ lines.push(` static let ${name} = ${hexToSwiftColor(value)}`);
689
+ }
690
+ }
691
+ lines.push(" }");
692
+ }
693
+ lines.push("");
694
+ lines.push(" // MARK: Spacing");
695
+ lines.push(" enum Spacing {");
696
+ for (const [key, value, isDeprecated] of spacing) {
697
+ const name = toSwiftName(key);
698
+ const numValue = parseFloat(value);
699
+ if (!isNaN(numValue)) {
700
+ if (isDeprecated) {
701
+ lines.push(` @available(*, deprecated, message: "This token has been removed from the design system")`);
702
+ lines.push(` static let ${name}: CGFloat = ${numValue}`);
703
+ } else {
704
+ lines.push(` static let ${name}: CGFloat = ${numValue}`);
705
+ }
706
+ }
707
+ }
708
+ lines.push(" }");
709
+ lines.push("");
710
+ lines.push(" // MARK: Typography");
711
+ lines.push(" enum Typography {");
712
+ for (const [key, value, isDeprecated] of typography) {
713
+ const name = toSwiftName(key);
714
+ if (isDeprecated) {
715
+ lines.push(` @available(*, deprecated, message: "This token has been removed from the design system")`);
716
+ }
717
+ if (key.includes("size")) {
718
+ const numValue = parseFloat(value);
719
+ if (!isNaN(numValue)) {
720
+ lines.push(` static let ${name}: CGFloat = ${numValue}`);
721
+ }
722
+ } else if (key.includes("weight")) {
723
+ lines.push(` static let ${name} = "${value}"`);
724
+ } else if (key.includes("family")) {
725
+ lines.push(` static let ${name} = "${value}"`);
726
+ }
727
+ }
728
+ lines.push(" }");
729
+ lines.push("");
730
+ lines.push(" // MARK: Other");
731
+ lines.push(" enum Other {");
732
+ for (const [key, value, isDeprecated] of other) {
733
+ const name = toSwiftName(key);
734
+ if (isDeprecated) {
735
+ lines.push(` @available(*, deprecated, message: "This token has been removed from the design system")`);
736
+ }
737
+ if (isColorValue(value)) {
738
+ lines.push(` static let ${name} = ${hexToSwiftColor(value)}`);
739
+ } else {
740
+ const numValue = parseFloat(value);
741
+ if (!isNaN(numValue)) {
742
+ lines.push(` static let ${name}: CGFloat = ${numValue}`);
743
+ } else {
744
+ lines.push(` static let ${name} = "${value}"`);
745
+ }
746
+ }
747
+ }
748
+ lines.push(" }");
749
+ lines.push("}");
750
+ lines.push("");
751
+ return lines.join("\n");
752
+ }
753
+ function toSwiftName2(cssVar) {
754
+ return cssVar.replace(/^--atmx-/, "").replace(/-([a-z])/g, (_, c) => c.toUpperCase());
755
+ }
756
+ function toKotlinName(cssVar) {
757
+ const camel = toSwiftName2(cssVar);
758
+ return camel.charAt(0).toUpperCase() + camel.slice(1);
759
+ }
760
+ function isColorValue2(value) {
761
+ return /^#[0-9A-Fa-f]{3,8}$/.test(value) || /^rgb/.test(value) || /^hsl/.test(value);
762
+ }
763
+ function hexToKotlinColor(hex) {
764
+ const clean = hex.replace("#", "").toUpperCase();
765
+ if (clean.length === 3) {
766
+ const r = clean[0], g = clean[1], b = clean[2];
767
+ return `Color(0xFF${r}${r}${g}${g}${b}${b})`;
768
+ }
769
+ if (clean.length === 6) {
770
+ return `Color(0xFF${clean})`;
771
+ }
772
+ if (clean.length === 8) {
773
+ const rgb = clean.substring(0, 6);
774
+ const alpha = clean.substring(6, 8);
775
+ return `Color(0x${alpha}${rgb})`;
776
+ }
777
+ return `Color.Transparent // Could not parse: ${hex}`;
778
+ }
779
+ function generateKotlinOutput(cssVariables, darkModeColors, deprecatedTokens = /* @__PURE__ */ new Map()) {
780
+ const lines = [
781
+ "// Atomix Design System Tokens",
782
+ "// Auto-generated - do not edit manually",
783
+ `// Synced: ${(/* @__PURE__ */ new Date()).toISOString()}`,
784
+ "",
785
+ "package com.atomix.design",
786
+ "",
787
+ "import androidx.compose.ui.graphics.Color",
788
+ "import androidx.compose.ui.unit.dp",
789
+ "import androidx.compose.ui.unit.sp",
790
+ "",
791
+ "object DesignTokens {",
792
+ "",
793
+ " // Light mode colors",
794
+ " object Colors {"
795
+ ];
796
+ const colors = [];
797
+ const spacing = [];
798
+ const typography = [];
799
+ const other = [];
800
+ for (const [key, value] of Object.entries(cssVariables)) {
801
+ const isDeprecated = false;
802
+ if (key.includes("-color-")) colors.push([key, value, isDeprecated]);
803
+ else if (key.includes("-spacing-")) spacing.push([key, value, isDeprecated]);
804
+ else if (key.includes("-typography-") || key.includes("-font-")) typography.push([key, value, isDeprecated]);
805
+ else other.push([key, value, isDeprecated]);
806
+ }
807
+ for (const [key, value] of deprecatedTokens.entries()) {
808
+ const isDeprecated = true;
809
+ if (key.includes("-color-")) colors.push([key, value, isDeprecated]);
810
+ else if (key.includes("-spacing-")) spacing.push([key, value, isDeprecated]);
811
+ else if (key.includes("-typography-") || key.includes("-font-")) typography.push([key, value, isDeprecated]);
812
+ else other.push([key, value, isDeprecated]);
813
+ }
814
+ colors.sort((a, b) => a[0].localeCompare(b[0]));
815
+ spacing.sort((a, b) => a[0].localeCompare(b[0]));
816
+ typography.sort((a, b) => a[0].localeCompare(b[0]));
817
+ other.sort((a, b) => a[0].localeCompare(b[0]));
818
+ for (const [key, value, isDeprecated] of colors) {
819
+ const name = toKotlinName(key);
820
+ if (isColorValue2(value)) {
821
+ if (isDeprecated) {
822
+ lines.push(` @Deprecated("This token has been removed from the design system")`);
823
+ lines.push(` val ${name} = ${hexToKotlinColor(value)}`);
824
+ } else {
825
+ lines.push(` val ${name} = ${hexToKotlinColor(value)}`);
826
+ }
827
+ }
828
+ }
829
+ lines.push(" }");
830
+ if (darkModeColors && Object.keys(darkModeColors).length > 0) {
831
+ lines.push("");
832
+ lines.push(" // Dark mode colors");
833
+ lines.push(" object ColorsDark {");
834
+ for (const [key, value] of Object.entries(darkModeColors)) {
835
+ const name = `Color${key.split("-").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join("")}`;
836
+ if (isColorValue2(value)) {
837
+ lines.push(` val ${name} = ${hexToKotlinColor(value)}`);
838
+ }
839
+ }
840
+ lines.push(" }");
841
+ }
842
+ lines.push("");
843
+ lines.push(" object Spacing {");
844
+ for (const [key, value, isDeprecated] of spacing) {
845
+ const name = toKotlinName(key);
846
+ const numValue = parseFloat(value);
847
+ if (!isNaN(numValue)) {
848
+ if (isDeprecated) {
849
+ lines.push(` @Deprecated("This token has been removed from the design system")`);
850
+ lines.push(` val ${name} = ${numValue}.dp`);
851
+ } else {
852
+ lines.push(` val ${name} = ${numValue}.dp`);
853
+ }
854
+ }
855
+ }
856
+ lines.push(" }");
857
+ lines.push("");
858
+ lines.push(" object Typography {");
859
+ for (const [key, value, isDeprecated] of typography) {
860
+ const name = toKotlinName(key);
861
+ if (isDeprecated) {
862
+ lines.push(` @Deprecated("This token has been removed from the design system")`);
863
+ }
864
+ if (key.includes("size")) {
865
+ const numValue = parseFloat(value);
866
+ if (!isNaN(numValue)) {
867
+ lines.push(` val ${name} = ${numValue}.sp`);
868
+ }
869
+ } else {
870
+ lines.push(` const val ${name} = "${value}"`);
871
+ }
872
+ }
873
+ lines.push(" }");
874
+ lines.push("");
875
+ lines.push(" object Other {");
876
+ for (const [key, value, isDeprecated] of other) {
877
+ const name = toKotlinName(key);
878
+ if (isDeprecated) {
879
+ lines.push(` @Deprecated("This token has been removed from the design system")`);
880
+ }
881
+ if (isColorValue2(value)) {
882
+ lines.push(` val ${name} = ${hexToKotlinColor(value)}`);
883
+ } else {
884
+ const numValue = parseFloat(value);
885
+ if (!isNaN(numValue)) {
886
+ lines.push(` val ${name} = ${numValue}.dp`);
887
+ } else {
888
+ lines.push(` const val ${name} = "${value}"`);
889
+ }
890
+ }
891
+ }
892
+ lines.push(" }");
893
+ lines.push("}");
894
+ lines.push("");
895
+ return lines.join("\n");
896
+ }
897
+ function toSwiftName3(cssVar) {
898
+ return cssVar.replace(/^--atmx-/, "").replace(/-([a-z])/g, (_, c) => c.toUpperCase());
899
+ }
900
+ function toDartName(cssVar) {
901
+ return toSwiftName3(cssVar);
902
+ }
903
+ function isColorValue3(value) {
904
+ return /^#[0-9A-Fa-f]{3,8}$/.test(value) || /^rgb/.test(value) || /^hsl/.test(value);
905
+ }
906
+ function hexToDartColor(hex) {
907
+ const clean = hex.replace("#", "").toUpperCase();
908
+ if (clean.length === 3) {
909
+ const r = clean[0], g = clean[1], b = clean[2];
910
+ return `Color(0xFF${r}${r}${g}${g}${b}${b})`;
911
+ }
912
+ if (clean.length === 6) {
913
+ return `Color(0xFF${clean})`;
914
+ }
915
+ if (clean.length === 8) {
916
+ const rgb = clean.substring(0, 6);
917
+ const alpha = clean.substring(6, 8);
918
+ return `Color(0x${alpha}${rgb})`;
919
+ }
920
+ return `Colors.transparent // Could not parse: ${hex}`;
921
+ }
922
+ function generateDartOutput(cssVariables, darkModeColors, deprecatedTokens = /* @__PURE__ */ new Map()) {
923
+ const lines = [
924
+ "// Atomix Design System Tokens",
925
+ "// Auto-generated - do not edit manually",
926
+ `// Synced: ${(/* @__PURE__ */ new Date()).toISOString()}`,
927
+ "",
928
+ "import 'package:flutter/material.dart';",
929
+ "",
930
+ "class DesignTokens {",
931
+ " DesignTokens._();",
932
+ "",
933
+ " // Colors (Light Mode)"
934
+ ];
935
+ const colors = [];
936
+ const spacing = [];
937
+ const typography = [];
938
+ const other = [];
939
+ for (const [key, value] of Object.entries(cssVariables)) {
940
+ const isDeprecated = false;
941
+ if (key.includes("-color-")) colors.push([key, value, isDeprecated]);
942
+ else if (key.includes("-spacing-")) spacing.push([key, value, isDeprecated]);
943
+ else if (key.includes("-typography-") || key.includes("-font-")) typography.push([key, value, isDeprecated]);
944
+ else other.push([key, value, isDeprecated]);
945
+ }
946
+ for (const [key, value] of deprecatedTokens.entries()) {
947
+ const isDeprecated = true;
948
+ if (key.includes("-color-")) colors.push([key, value, isDeprecated]);
949
+ else if (key.includes("-spacing-")) spacing.push([key, value, isDeprecated]);
950
+ else if (key.includes("-typography-") || key.includes("-font-")) typography.push([key, value, isDeprecated]);
951
+ else other.push([key, value, isDeprecated]);
952
+ }
953
+ colors.sort((a, b) => a[0].localeCompare(b[0]));
954
+ spacing.sort((a, b) => a[0].localeCompare(b[0]));
955
+ typography.sort((a, b) => a[0].localeCompare(b[0]));
956
+ other.sort((a, b) => a[0].localeCompare(b[0]));
957
+ for (const [key, value, isDeprecated] of colors) {
958
+ const name = toDartName(key);
959
+ if (isColorValue3(value)) {
960
+ if (isDeprecated) {
961
+ lines.push(` @Deprecated('This token has been removed from the design system')`);
962
+ lines.push(` static const ${name} = ${hexToDartColor(value)};`);
963
+ } else {
964
+ lines.push(` static const ${name} = ${hexToDartColor(value)};`);
965
+ }
966
+ }
967
+ }
968
+ if (darkModeColors && Object.keys(darkModeColors).length > 0) {
969
+ lines.push("");
970
+ lines.push(" // Colors (Dark Mode)");
971
+ for (const [key, value] of Object.entries(darkModeColors)) {
972
+ const name = `color${key.split("-").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join("")}Dark`;
973
+ if (isColorValue3(value)) {
974
+ lines.push(` static const ${name} = ${hexToDartColor(value)};`);
975
+ }
976
+ }
977
+ }
978
+ lines.push("");
979
+ lines.push(" // Spacing");
980
+ for (const [key, value, isDeprecated] of spacing) {
981
+ const name = toDartName(key);
982
+ const numValue = parseFloat(value);
983
+ if (!isNaN(numValue)) {
984
+ if (isDeprecated) {
985
+ lines.push(` @Deprecated('This token has been removed from the design system')`);
986
+ lines.push(` static const double ${name} = ${numValue};`);
987
+ } else {
988
+ lines.push(` static const double ${name} = ${numValue};`);
989
+ }
990
+ }
991
+ }
992
+ lines.push("");
993
+ lines.push(" // Typography");
994
+ for (const [key, value, isDeprecated] of typography) {
995
+ const name = toDartName(key);
996
+ if (isDeprecated) {
997
+ lines.push(` @Deprecated('This token has been removed from the design system')`);
998
+ }
999
+ if (key.includes("size")) {
1000
+ const numValue = parseFloat(value);
1001
+ if (!isNaN(numValue)) {
1002
+ lines.push(` static const double ${name} = ${numValue};`);
1003
+ }
1004
+ } else {
1005
+ lines.push(` static const String ${name} = '${value}';`);
1006
+ }
1007
+ }
1008
+ lines.push("");
1009
+ lines.push(" // Other");
1010
+ for (const [key, value, isDeprecated] of other) {
1011
+ const name = toDartName(key);
1012
+ if (isDeprecated) {
1013
+ lines.push(` @Deprecated('This token has been removed from the design system')`);
1014
+ }
1015
+ if (isColorValue3(value)) {
1016
+ lines.push(` static const ${name} = ${hexToDartColor(value)};`);
1017
+ } else {
1018
+ const numValue = parseFloat(value);
1019
+ if (!isNaN(numValue)) {
1020
+ lines.push(` static const double ${name} = ${numValue};`);
1021
+ } else {
1022
+ lines.push(` static const String ${name} = '${value}';`);
1023
+ }
1024
+ }
1025
+ }
1026
+ lines.push("}");
1027
+ lines.push("");
1028
+ return lines.join("\n");
1029
+ }
1030
+ function formatSyncResponse(options) {
1031
+ const {
1032
+ data,
1033
+ output,
1034
+ format,
1035
+ dsTokenCount,
1036
+ deprecatedCount,
1037
+ deprecatedTokens,
1038
+ diff,
1039
+ changes = [],
1040
+ fileExists,
1041
+ rulesResults = [],
1042
+ governanceChanges = [],
1043
+ changeSummary,
1044
+ hasRefactorRecommendation = false,
1045
+ deprecatedTokenCount = 0
1046
+ } = options;
1047
+ const lastUpdated = data.meta.exportedAt ? new Date(data.meta.exportedAt).toLocaleString() : "N/A";
1048
+ let response = `\u2713 Synced ${dsTokenCount} tokens to ${output}
1049
+ `;
1050
+ response += `Format: ${format}
1051
+ `;
1052
+ response += `Design System: ${data.meta.name} (v${data.meta.version})
1053
+ `;
1054
+ if (deprecatedCount > 0) {
1055
+ response += `Tokens: ${dsTokenCount} active, ${deprecatedCount} deprecated (run /refactor to migrate)
1056
+ `;
1057
+ } else {
1058
+ response += `Tokens: ${dsTokenCount}
1059
+ `;
1060
+ }
1061
+ response += `Version: ${data.meta.version}
1062
+ `;
1063
+ response += `Last updated: ${lastUpdated}
1064
+ `;
1065
+ if (deprecatedCount > 0) {
1066
+ response += `
1067
+ \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
1068
+ `;
1069
+ response += `\u{1F4CB} DEPRECATED TOKENS (${deprecatedCount})
1070
+ `;
1071
+ response += `\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
1072
+
1073
+ `;
1074
+ response += `These tokens are no longer in the design system but are preserved in your file for backward compatibility.
1075
+ `;
1076
+ response += `Run \`/refactor\` to find and migrate usage in your codebase.
1077
+
1078
+ `;
1079
+ const deprecatedTokenList = Array.from(deprecatedTokens.keys()).sort();
1080
+ deprecatedTokenList.forEach((token, index) => {
1081
+ const value = deprecatedTokens.get(token);
1082
+ response += ` ${index + 1}. ${token}`;
1083
+ if (value) {
1084
+ response += ` = ${value}`;
1085
+ }
1086
+ response += `
1087
+ `;
1088
+ });
1089
+ }
1090
+ const newTokenList = [];
1091
+ if (diff) {
1092
+ newTokenList.push(...diff.added, ...diff.addedDark);
1093
+ }
1094
+ if (changeSummary && changeSummary.includes("\u2795 Added:")) {
1095
+ const addedSection = changeSummary.match(/➕ Added: \d+ token\(s\)([\s\S]*?)(?=➖|🔄|📝|$)/);
1096
+ if (addedSection) {
1097
+ const addedLines = addedSection[0].match(/ - (--[^\n]+)/g) || [];
1098
+ addedLines.forEach((line) => {
1099
+ const token = line.replace(/ - /, "").trim();
1100
+ if (token && !newTokenList.includes(token)) {
1101
+ newTokenList.push(token);
1102
+ }
1103
+ });
1104
+ }
1105
+ }
1106
+ if (newTokenList.length > 0) {
1107
+ response += `
1108
+ \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
1109
+ `;
1110
+ response += `\u2728 NEW TOKENS (${newTokenList.length})
1111
+ `;
1112
+ response += `\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
1113
+
1114
+ `;
1115
+ newTokenList.sort().forEach((token, index) => {
1116
+ response += ` ${index + 1}. ${token}
1117
+ `;
1118
+ });
1119
+ }
1120
+ const modifiedFiles = [output];
1121
+ rulesResults.forEach((result) => {
1122
+ if (result.success) {
1123
+ const fullPath = path3.resolve(process.cwd(), result.path);
1124
+ if (!modifiedFiles.includes(fullPath)) {
1125
+ modifiedFiles.push(fullPath);
1126
+ }
1127
+ }
1128
+ });
1129
+ response += `
1130
+ \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
1131
+ `;
1132
+ response += `\u{1F4C1} MODIFIED FILES (${modifiedFiles.length})
1133
+ `;
1134
+ response += `\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
1135
+
1136
+ `;
1137
+ modifiedFiles.forEach((file, index) => {
1138
+ const relativePath = path3.relative(process.cwd(), file);
1139
+ response += ` ${index + 1}. ${relativePath}
1140
+ `;
1141
+ });
1142
+ if (governanceChanges.length > 0) {
1143
+ response += `
1144
+ \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
1145
+ `;
1146
+ response += `\u{1F4DD} AI RULES CHANGES
1147
+ `;
1148
+ response += `\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
1149
+
1150
+ `;
1151
+ response += `The following AI guidance sections have been updated:
1152
+
1153
+ `;
1154
+ const capitalize = (str) => str.charAt(0).toUpperCase() + str.slice(1);
1155
+ governanceChanges.forEach((foundation, index) => {
1156
+ const displayName = foundation === "general" ? "General Rules" : capitalize(foundation);
1157
+ response += ` ${index + 1}. ${displayName}
1158
+ `;
1159
+ });
1160
+ response += `
1161
+ These changes are reflected in your AI tool rules files (e.g., .cursorrules).
1162
+ `;
1163
+ response += `Review the updated rules files to see the new guidance.
1164
+ `;
1165
+ }
1166
+ if (diff) {
1167
+ const lightChanges = diff.added.length + diff.modified.length;
1168
+ const darkChanges = diff.addedDark.length + diff.modifiedDark.length;
1169
+ if (lightChanges > 0 || darkChanges > 0 || deprecatedCount > 0) {
1170
+ response += `
1171
+ \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
1172
+ `;
1173
+ response += `\u{1F4CA} DETAILED CHANGES
1174
+ `;
1175
+ response += `\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
1176
+
1177
+ `;
1178
+ const lightSummary = lightChanges > 0 ? `Light: ${diff.modified.length} modified, ${diff.added.length} added` : "";
1179
+ const darkSummary = darkChanges > 0 ? `Dark: ${diff.modifiedDark.length} modified, ${diff.addedDark.length} added` : "";
1180
+ const deprecatedSummary = deprecatedCount > 0 ? `${deprecatedCount} deprecated (use /refactor)` : "";
1181
+ const diffSummary = [lightSummary, darkSummary, deprecatedSummary].filter(Boolean).join(" | ");
1182
+ response += `${diffSummary}
1183
+ `;
1184
+ if (changes.length > 0 && changes.length <= 10) {
1185
+ response += "\nModified tokens:\n";
1186
+ for (const { key, old: oldVal, new: newVal } of changes) {
1187
+ response += ` ${key}: ${oldVal} \u2192 ${newVal}
1188
+ `;
1189
+ }
1190
+ }
1191
+ }
1192
+ } else if (!fileExists) {
1193
+ response += `
1194
+ (New file created)
1195
+ `;
1196
+ }
1197
+ if (hasRefactorRecommendation && deprecatedTokenCount > 0) {
1198
+ response += `
1199
+ \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
1200
+ `;
1201
+ response += `\u{1F4A1} NEXT STEP
1202
+ `;
1203
+ response += `\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
1204
+
1205
+ `;
1206
+ response += `${deprecatedTokenCount} token(s) have been deprecated.
1207
+ `;
1208
+ response += `Your codebase may still reference these deprecated tokens.
1209
+
1210
+ `;
1211
+ response += `Run \`/refactor\` to:
1212
+ `;
1213
+ response += ` \u2022 Scan your codebase for deprecated token usage
1214
+ `;
1215
+ response += ` \u2022 See which files need updates
1216
+ `;
1217
+ response += ` \u2022 Review and apply changes with your confirmation
1218
+ `;
1219
+ }
1220
+ return response;
1221
+ }
1222
+ function getTokenByPath(tokens, path5) {
1223
+ const parts = path5.split(".");
1224
+ let current = tokens;
1225
+ for (const part of parts) {
1226
+ if (current && typeof current === "object" && part in current) {
1227
+ current = current[part];
1228
+ } else {
1229
+ return void 0;
1230
+ }
1231
+ }
1232
+ return current;
1233
+ }
1234
+ function flattenTokens(obj, prefix = "") {
1235
+ const results = [];
1236
+ if (obj && typeof obj === "object" && !Array.isArray(obj)) {
1237
+ for (const [key, value] of Object.entries(obj)) {
1238
+ const newPath = prefix ? `${prefix}.${key}` : key;
1239
+ if (value && typeof value === "object" && !Array.isArray(value)) {
1240
+ results.push(...flattenTokens(value, newPath));
1241
+ } else {
1242
+ results.push({ path: newPath, value });
1243
+ }
1244
+ }
1245
+ }
1246
+ return results;
1247
+ }
1248
+ function searchTokens(tokens, query) {
1249
+ const flat = flattenTokens(tokens);
1250
+ const lowerQuery = query.toLowerCase();
1251
+ return flat.filter(({ path: path5, value }) => {
1252
+ const pathMatch = path5.toLowerCase().includes(lowerQuery);
1253
+ const valueMatch = String(value).toLowerCase().includes(lowerQuery);
1254
+ return pathMatch || valueMatch;
1255
+ });
1256
+ }
1257
+ function countTokens(tokens, prefix = "") {
1258
+ let count = 0;
1259
+ for (const [key, value] of Object.entries(tokens)) {
1260
+ if (value && typeof value === "object" && !Array.isArray(value)) {
1261
+ count += countTokens(value, `${prefix}${key}.`);
1262
+ } else if (value !== void 0 && value !== null) {
1263
+ count++;
1264
+ }
1265
+ }
1266
+ return count;
1267
+ }
1268
+ function getTokenStats(data) {
1269
+ const byCategory = {};
1270
+ let total = 0;
1271
+ for (const [category, value] of Object.entries(data.tokens)) {
1272
+ if (value && typeof value === "object") {
1273
+ const count = countTokens(value);
1274
+ byCategory[category] = count;
1275
+ total += count;
1276
+ }
1277
+ }
1278
+ return {
1279
+ total,
1280
+ byCategory,
1281
+ cssVariables: Object.keys(data.cssVariables).length,
1282
+ governanceRules: data.governance.rules.length
1283
+ };
1284
+ }
1285
+
1286
+ // src/index.ts
1287
+ import * as path2 from "path";
1288
+ import * as fs2 from "fs";
37
1289
  function parseArgs() {
38
1290
  const args = process.argv.slice(2);
39
1291
  let dsId2 = null;
@@ -93,7 +1345,7 @@ var TOKEN_CATEGORIES = ["colors", "typography", "spacing", "sizing", "shadows",
93
1345
  var server = new Server(
94
1346
  {
95
1347
  name: "atomix-mcp-user",
96
- version: "1.0.9"
1348
+ version: "1.0.10"
97
1349
  },
98
1350
  {
99
1351
  capabilities: {
@@ -265,27 +1517,27 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
265
1517
  const data = await fetchDesignSystemForMCP(shouldForceRefresh);
266
1518
  switch (name) {
267
1519
  case "getToken": {
268
- const path2 = args?.path;
269
- const value = getTokenByPath(data.tokens, path2);
1520
+ const path4 = args?.path;
1521
+ const value = getTokenByPath(data.tokens, path4);
270
1522
  if (value === void 0) {
271
1523
  return {
272
1524
  content: [{
273
1525
  type: "text",
274
1526
  text: JSON.stringify({
275
- error: `Token not found: ${path2}`,
1527
+ error: `Token not found: ${path4}`,
276
1528
  suggestion: "Use listTokens or searchTokens to find available tokens.",
277
1529
  availableCategories: TOKEN_CATEGORIES
278
1530
  }, null, 2)
279
1531
  }]
280
1532
  };
281
1533
  }
282
- const cssVarKey = `--atmx-${path2.replace(/\./g, "-")}`;
1534
+ const cssVarKey = `--atmx-${path4.replace(/\./g, "-")}`;
283
1535
  const cssVar = data.cssVariables[cssVarKey];
284
1536
  return {
285
1537
  content: [{
286
1538
  type: "text",
287
1539
  text: JSON.stringify({
288
- path: path2,
1540
+ path: path4,
289
1541
  value,
290
1542
  cssVariable: cssVar || `var(${cssVarKey})`,
291
1543
  usage: `style={{ property: "var(${cssVarKey})" }}`
@@ -312,13 +1564,13 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
312
1564
  };
313
1565
  }
314
1566
  const flat = flattenTokens(tokensToList);
315
- const tokensWithCssVars = flat.map(({ path: path2, value }) => {
316
- const fullPath = subcategory ? `${category}.${subcategory}.${path2}` : `${category}.${path2}`;
1567
+ const tokensWithCssVars = flat.map(({ path: path4, value }) => {
1568
+ const fullPath = subcategory ? `${category}.${subcategory}.${path4}` : `${category}.${path4}`;
317
1569
  let cssVar;
318
1570
  if (category === "colors" && subcategory === "static.brand") {
319
- cssVar = data.cssVariables[`--atmx-color-brand-${path2}`];
1571
+ cssVar = data.cssVariables[`--atmx-color-brand-${path4}`];
320
1572
  } else if (category === "colors" && subcategory?.startsWith("modes.")) {
321
- cssVar = data.cssVariables[`--atmx-color-${path2}`];
1573
+ cssVar = data.cssVariables[`--atmx-color-${path4}`];
322
1574
  } else {
323
1575
  const cssVarKey = `--atmx-${fullPath.replace(/\./g, "-")}`;
324
1576
  cssVar = data.cssVariables[cssVarKey];
@@ -638,12 +1890,12 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
638
1890
  }]
639
1891
  };
640
1892
  }
641
- const outputPath = path.resolve(process.cwd(), output);
642
- const fileExists = fs.existsSync(outputPath);
1893
+ const outputPath = path2.resolve(process.cwd(), output);
1894
+ const fileExists = fs2.existsSync(outputPath);
643
1895
  const deprecatedTokens = /* @__PURE__ */ new Map();
644
1896
  const existingTokens = /* @__PURE__ */ new Map();
645
1897
  if (fileExists && ["css", "scss", "less"].includes(format)) {
646
- const oldContent = fs.readFileSync(outputPath, "utf-8");
1898
+ const oldContent = fs2.readFileSync(outputPath, "utf-8");
647
1899
  const oldVarPattern = /(?:^|\n)\s*(?:\/\*[^*]*\*+(?:[^/*][^*]*\*+)*\/\s*)?(--[a-zA-Z0-9-]+):\s*([^;]+);/gm;
648
1900
  let match;
649
1901
  while ((match = oldVarPattern.exec(oldContent)) !== null) {
@@ -696,7 +1948,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
696
1948
  let changes = [];
697
1949
  let diff;
698
1950
  if (fileExists && ["css", "scss", "less"].includes(format)) {
699
- const oldContent = fs.readFileSync(outputPath, "utf-8");
1951
+ const oldContent = fs2.readFileSync(outputPath, "utf-8");
700
1952
  diff = diffTokens(oldContent, mergedCssVariables, format, darkModeColors?.dark);
701
1953
  const lightChanges = diff.added.length + diff.modified.length;
702
1954
  const darkChanges = diff.addedDark.length + diff.modifiedDark.length;
@@ -736,11 +1988,11 @@ Last updated: ${lastUpdated}`
736
1988
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
737
1989
  };
738
1990
  }
739
- const outputDir = path.dirname(outputPath);
740
- if (!fs.existsSync(outputDir)) {
741
- fs.mkdirSync(outputDir, { recursive: true });
1991
+ const outputDir = path2.dirname(outputPath);
1992
+ if (!fs2.existsSync(outputDir)) {
1993
+ fs2.mkdirSync(outputDir, { recursive: true });
742
1994
  }
743
- fs.writeFileSync(outputPath, newContent);
1995
+ fs2.writeFileSync(outputPath, newContent);
744
1996
  let rulesResults = [];
745
1997
  try {
746
1998
  rulesResults = await syncRulesFiles({