mcp-tailwindcss 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/dist/index.js ADDED
@@ -0,0 +1,1357 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
4
+ import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
5
+ import * as fs from 'fs';
6
+ import * as path from 'path';
7
+ import { fileURLToPath } from 'url';
8
+ import { AstParser, } from './ast-parser.js';
9
+ import { checkAndUpdate, checkForUpdates, getRepositoryStatus, scheduleUpdateCheck, ensureRepository, } from './auto-updater.js';
10
+ const __filename = fileURLToPath(import.meta.url);
11
+ const __dirname = path.dirname(__filename);
12
+ let TAILWIND_SRC_PATH = process.env.TAILWIND_SRC_PATH || '';
13
+ const CATEGORY_EMOJI = {
14
+ interface: '📋',
15
+ type: '📝',
16
+ enum: '🔢',
17
+ function: '⚡',
18
+ class: '🏛️',
19
+ variable: '📦',
20
+ namespace: '📁',
21
+ 're-export': '🔗',
22
+ };
23
+ const CATEGORY_LABELS = {
24
+ interface: 'Interfaces',
25
+ type: 'Type Aliases',
26
+ enum: 'Enumerations',
27
+ function: 'Functions',
28
+ class: 'Classes',
29
+ variable: 'Variables/Constants',
30
+ namespace: 'Namespaces',
31
+ 're-export': 'Re-exports',
32
+ };
33
+ const mcpServer = new McpServer({
34
+ name: 'mcp-tailwindcss',
35
+ version: '1.0.0',
36
+ }, {
37
+ capabilities: {
38
+ tools: {},
39
+ resources: {},
40
+ },
41
+ });
42
+ function getDirectoryTree(dirPath, prefix = '') {
43
+ let result = '';
44
+ const items = fs.readdirSync(dirPath, { withFileTypes: true });
45
+ const dirs = items.filter((i) => i.isDirectory() && !i.name.startsWith('.'));
46
+ const files = items.filter((i) => i.isFile() && (i.name.endsWith('.ts') || i.name.endsWith('.js')));
47
+ for (const file of files) {
48
+ result += `${prefix}├── ${file.name}\n`;
49
+ }
50
+ for (let i = 0; i < dirs.length; i++) {
51
+ const dir = dirs[i];
52
+ const isLast = i === dirs.length - 1;
53
+ result += `${prefix}${isLast ? '└── ' : '├── '}${dir.name}/\n`;
54
+ result += getDirectoryTree(path.join(dirPath, dir.name), prefix + (isLast ? ' ' : '│ '));
55
+ }
56
+ return result;
57
+ }
58
+ function formatProperty(prop) {
59
+ if (prop.isMethod || prop.isCallSignature) {
60
+ const params = prop.parameters?.join(', ') || '';
61
+ return `${prop.name}(${params}): ${prop.returnType || prop.type}`;
62
+ }
63
+ if (prop.isIndexSignature) {
64
+ return `${prop.name}: ${prop.type}`;
65
+ }
66
+ const optional = prop.optional ? '?' : '';
67
+ const readonly = prop.readonly ? 'readonly ' : '';
68
+ return `${readonly}${prop.name}${optional}: ${prop.type}`;
69
+ }
70
+ function formatExtractedType(type, detailed = false) {
71
+ let result = `### ${CATEGORY_EMOJI[type.kind]} ${type.kind}: \`${type.name}\`\n\n`;
72
+ result += `**Arquivo:** \`${type.file}\`${type.lineNumber ? ` (linha ${type.lineNumber})` : ''}\n`;
73
+ result += `**Módulo:** ${type.module}\n\n`;
74
+ if (type.docs) {
75
+ result += `> ${type.docs}\n\n`;
76
+ }
77
+ result += '```typescript\n' + type.signature + '\n```\n\n';
78
+ if (detailed) {
79
+ if (type.typeParameters && type.typeParameters.length > 0) {
80
+ result += '**Type Parameters:**\n';
81
+ for (const tp of type.typeParameters) {
82
+ result += `- \`${tp.name}\``;
83
+ if (tp.constraint)
84
+ result += ` extends \`${tp.constraint}\``;
85
+ if (tp.default)
86
+ result += ` = \`${tp.default}\``;
87
+ result += '\n';
88
+ }
89
+ result += '\n';
90
+ }
91
+ if (type.extends && type.extends.length > 0) {
92
+ result += `**Extends:** ${type.extends.map((e) => `\`${e}\``).join(', ')}\n\n`;
93
+ }
94
+ if (type.implements && type.implements.length > 0) {
95
+ result += `**Implements:** ${type.implements.map((i) => `\`${i}\``).join(', ')}\n\n`;
96
+ }
97
+ if (type.properties && type.properties.length > 0) {
98
+ result += '**Properties:**\n';
99
+ for (const prop of type.properties.slice(0, 15)) {
100
+ result += `- \`${formatProperty(prop)}\`\n`;
101
+ if (prop.docs)
102
+ result += ` > ${prop.docs}\n`;
103
+ }
104
+ if (type.properties.length > 15) {
105
+ result += `- ... e mais ${type.properties.length - 15} propriedades\n`;
106
+ }
107
+ result += '\n';
108
+ }
109
+ if (type.methods && type.methods.length > 0) {
110
+ result += '**Methods:**\n';
111
+ for (const method of type.methods.slice(0, 15)) {
112
+ result += `- \`${formatProperty(method)}\`\n`;
113
+ if (method.docs)
114
+ result += ` > ${method.docs}\n`;
115
+ }
116
+ if (type.methods.length > 15) {
117
+ result += `- ... e mais ${type.methods.length - 15} métodos\n`;
118
+ }
119
+ result += '\n';
120
+ }
121
+ if (type.members && type.members.length > 0) {
122
+ result += '**Members:**\n';
123
+ for (const member of type.members.slice(0, 20)) {
124
+ result += `- \`${member}\`\n`;
125
+ }
126
+ if (type.members.length > 20) {
127
+ result += `- ... e mais ${type.members.length - 20} membros\n`;
128
+ }
129
+ result += '\n';
130
+ }
131
+ if (type.value) {
132
+ result += `**Value:** \`${type.value}\`\n\n`;
133
+ }
134
+ }
135
+ return result;
136
+ }
137
+ function formatStatistics(stats) {
138
+ let result = '# 📊 Estatísticas da Biblioteca Tailwind CSS\n\n';
139
+ result += `**Total de Declarações:** ${stats.totalDeclarations}\n\n`;
140
+ result += '## Por Categoria\n\n';
141
+ result += '| Categoria | Quantidade | % |\n';
142
+ result += '|-----------|------------|---|\n';
143
+ for (const [kind, count] of Object.entries(stats.byKind)) {
144
+ const percentage = ((count / stats.totalDeclarations) * 100).toFixed(1);
145
+ result += `| ${CATEGORY_EMOJI[kind]} ${CATEGORY_LABELS[kind]} | ${count} | ${percentage}% |\n`;
146
+ }
147
+ result += '\n## Por Módulo\n\n';
148
+ result += '| Módulo | Total | Interfaces | Types | Functions | Enums | Variables | Classes |\n';
149
+ result += '|--------|-------|------------|-------|-----------|-------|-----------|----------|\n';
150
+ for (const mod of stats.byModule) {
151
+ result += `| **${mod.module}** | ${mod.total} | ${mod.interfaces} | ${mod.types} | ${mod.functions} | ${mod.enums} | ${mod.variables} | ${mod.classes} |\n`;
152
+ }
153
+ result += '\n## Top Interfaces\n';
154
+ for (const name of stats.topInterfaces) {
155
+ result += `- \`${name}\`\n`;
156
+ }
157
+ result += '\n## Top Types\n';
158
+ for (const name of stats.topTypes) {
159
+ result += `- \`${name}\`\n`;
160
+ }
161
+ result += '\n## Top Functions\n';
162
+ for (const name of stats.topFunctions) {
163
+ result += `- \`${name}\`\n`;
164
+ }
165
+ return result;
166
+ }
167
+ function formatDependencies(deps) {
168
+ let result = '# 🔗 Análise de Dependências\n\n';
169
+ for (const dep of deps) {
170
+ result += `## 📁 ${dep.module}\n\n`;
171
+ if (dep.exports.length > 0) {
172
+ result += `**Exports (${dep.exports.length}):** `;
173
+ result += dep.exports.slice(0, 10).map((e) => `\`${e}\``).join(', ');
174
+ if (dep.exports.length > 10) {
175
+ result += `, ... (+${dep.exports.length - 10})`;
176
+ }
177
+ result += '\n\n';
178
+ }
179
+ if (dep.reExportsFrom.length > 0) {
180
+ result += `**Re-exports from:** ${dep.reExportsFrom.map((r) => `\`${r}\``).join(', ')}\n\n`;
181
+ }
182
+ }
183
+ return result;
184
+ }
185
+ mcpServer.server.setRequestHandler(ListToolsRequestSchema, async () => {
186
+ return {
187
+ tools: [
188
+ {
189
+ name: 'tailwind_estrutura',
190
+ description: 'Lista a estrutura de arquivos do pacote Tailwind CSS (packages/tailwindcss/src). Útil para entender a organização do código.',
191
+ inputSchema: {
192
+ type: 'object',
193
+ properties: {
194
+ subpasta: {
195
+ type: 'string',
196
+ description: 'Subpasta específica para listar (ex: utils, compat). Deixe vazio para listar tudo.',
197
+ },
198
+ },
199
+ required: [],
200
+ },
201
+ },
202
+ {
203
+ name: 'tailwind_ler_arquivo',
204
+ description: 'Lê o conteúdo de um arquivo específico da biblioteca Tailwind CSS.',
205
+ inputSchema: {
206
+ type: 'object',
207
+ properties: {
208
+ caminho: {
209
+ type: 'string',
210
+ description: 'Caminho relativo do arquivo dentro de src/ (ex: utils/resolve-config.ts)',
211
+ },
212
+ },
213
+ required: ['caminho'],
214
+ },
215
+ },
216
+ {
217
+ name: 'tailwind_extrair_tipos',
218
+ description: 'Extrai interfaces, types, enums, funções, classes, variáveis e namespaces exportados do Tailwind usando análise de AST. Economiza tokens mostrando apenas assinaturas.',
219
+ inputSchema: {
220
+ type: 'object',
221
+ properties: {
222
+ modulo: {
223
+ type: 'string',
224
+ description: 'Nome do módulo para extrair tipos (ex: utils, compat, intellisense). Deixe vazio para todos.',
225
+ },
226
+ apenas_kind: {
227
+ type: 'string',
228
+ enum: ['interface', 'type', 'enum', 'function', 'class', 'variable', 'namespace', 're-export'],
229
+ description: 'Filtrar por tipo específico de declaração.',
230
+ },
231
+ },
232
+ required: [],
233
+ },
234
+ },
235
+ {
236
+ name: 'tailwind_buscar_tipo',
237
+ description: 'Busca a definição de um tipo específico do Tailwind pelo nome. Retorna assinatura completa, propriedades, métodos e documentação.',
238
+ inputSchema: {
239
+ type: 'object',
240
+ properties: {
241
+ nome: {
242
+ type: 'string',
243
+ description: 'Nome do tipo a buscar (ex: Config, PluginCreator, ThemeValue)',
244
+ },
245
+ },
246
+ required: ['nome'],
247
+ },
248
+ },
249
+ {
250
+ name: 'tailwind_buscar_fuzzy',
251
+ description: 'Busca tipos do Tailwind usando correspondência aproximada. Útil quando não sabe o nome exato.',
252
+ inputSchema: {
253
+ type: 'object',
254
+ properties: {
255
+ query: {
256
+ type: 'string',
257
+ description: 'Termo de busca (ex: "message send", "auth state", "socket config")',
258
+ },
259
+ limite: {
260
+ type: 'number',
261
+ description: 'Número máximo de resultados (default: 20)',
262
+ },
263
+ },
264
+ required: ['query'],
265
+ },
266
+ },
267
+ {
268
+ name: 'tailwind_listar_exports',
269
+ description: 'Lista todos os exports públicos do Tailwind, agrupados por módulo e categoria.',
270
+ inputSchema: {
271
+ type: 'object',
272
+ properties: {},
273
+ required: [],
274
+ },
275
+ },
276
+ {
277
+ name: 'tailwind_categorias',
278
+ description: 'Lista declarações de uma categoria específica (interfaces, types, enums, functions, classes, variables, namespaces) do Tailwind.',
279
+ inputSchema: {
280
+ type: 'object',
281
+ properties: {
282
+ categoria: {
283
+ type: 'string',
284
+ enum: ['interface', 'type', 'enum', 'function', 'class', 'variable', 'namespace', 're-export'],
285
+ description: 'Categoria de declarações para listar.',
286
+ },
287
+ modulo: {
288
+ type: 'string',
289
+ description: 'Filtrar por módulo específico (opcional).',
290
+ },
291
+ },
292
+ required: ['categoria'],
293
+ },
294
+ },
295
+ {
296
+ name: 'tailwind_constantes',
297
+ description: 'Lista todas as constantes e variáveis exportadas do Tailwind (configurações, defaults, etc).',
298
+ inputSchema: {
299
+ type: 'object',
300
+ properties: {
301
+ modulo: {
302
+ type: 'string',
303
+ description: 'Filtrar por módulo específico (ex: Defaults, WABinary).',
304
+ },
305
+ },
306
+ required: [],
307
+ },
308
+ },
309
+ {
310
+ name: 'tailwind_hierarquia',
311
+ description: 'Mostra a hierarquia de herança de um tipo (extends/implements, pais e filhos).',
312
+ inputSchema: {
313
+ type: 'object',
314
+ properties: {
315
+ nome: {
316
+ type: 'string',
317
+ description: 'Nome do tipo para analisar hierarquia.',
318
+ },
319
+ },
320
+ required: ['nome'],
321
+ },
322
+ },
323
+ {
324
+ name: 'tailwind_estatisticas',
325
+ description: 'Retorna estatísticas detalhadas do Tailwind: contagem por categoria, por módulo, top tipos.',
326
+ inputSchema: {
327
+ type: 'object',
328
+ properties: {},
329
+ required: [],
330
+ },
331
+ },
332
+ {
333
+ name: 'tailwind_dependencias',
334
+ description: 'Analisa as dependências entre módulos do Tailwind: o que cada módulo exporta e re-exporta.',
335
+ inputSchema: {
336
+ type: 'object',
337
+ properties: {},
338
+ required: [],
339
+ },
340
+ },
341
+ {
342
+ name: 'tailwind_enums',
343
+ description: 'Lista todas as enumerações exportadas do Tailwind com seus valores.',
344
+ inputSchema: {
345
+ type: 'object',
346
+ properties: {},
347
+ required: [],
348
+ },
349
+ },
350
+ {
351
+ name: 'tailwind_interfaces',
352
+ description: 'Lista todas as interfaces do Tailwind com suas propriedades e métodos.',
353
+ inputSchema: {
354
+ type: 'object',
355
+ properties: {
356
+ modulo: {
357
+ type: 'string',
358
+ description: 'Filtrar por módulo específico.',
359
+ },
360
+ detalhado: {
361
+ type: 'boolean',
362
+ description: 'Incluir propriedades e métodos (default: false).',
363
+ },
364
+ },
365
+ required: [],
366
+ },
367
+ },
368
+ {
369
+ name: 'tailwind_funcoes',
370
+ description: 'Lista todas as funções exportadas do Tailwind com suas assinaturas.',
371
+ inputSchema: {
372
+ type: 'object',
373
+ properties: {
374
+ modulo: {
375
+ type: 'string',
376
+ description: 'Filtrar por módulo específico (ex: Utils, Socket).',
377
+ },
378
+ },
379
+ required: [],
380
+ },
381
+ },
382
+ {
383
+ name: 'tailwind_check_updates',
384
+ description: 'Verifica se há atualizações disponíveis no repositório oficial do Tailwind CSS (GitHub). Não aplica atualizações, apenas verifica.',
385
+ inputSchema: {
386
+ type: 'object',
387
+ properties: {},
388
+ required: [],
389
+ },
390
+ },
391
+ {
392
+ name: 'tailwind_update',
393
+ description: 'Atualiza o repositório local do Tailwind CSS para a versão mais recente do GitHub. Executa git pull automaticamente.',
394
+ inputSchema: {
395
+ type: 'object',
396
+ properties: {},
397
+ required: [],
398
+ },
399
+ },
400
+ {
401
+ name: 'tailwind_status',
402
+ description: 'Mostra o status atual do repositório Tailwind: SHA do commit, se há atualizações pendentes, caminho do repositório.',
403
+ inputSchema: {
404
+ type: 'object',
405
+ properties: {},
406
+ required: [],
407
+ },
408
+ },
409
+ {
410
+ name: 'tailwind_integracoes',
411
+ description: 'Passo a passo e snippets para integrar Tailwind CSS com frameworks (Vite, Next.js, Nuxt, SvelteKit, Remix, Astro, Vue, React).',
412
+ inputSchema: {
413
+ type: 'object',
414
+ properties: {
415
+ framework: {
416
+ type: 'string',
417
+ description: 'Framework alvo (vite, next, nuxt, sveltekit, remix, astro, vue, react).',
418
+ },
419
+ },
420
+ required: ['framework'],
421
+ },
422
+ },
423
+ ],
424
+ };
425
+ });
426
+ mcpServer.server.setRequestHandler(CallToolRequestSchema, async (request) => {
427
+ const { name, arguments: args } = request.params;
428
+ try {
429
+ switch (name) {
430
+ case 'tailwind_estrutura': {
431
+ const subpasta = args?.subpasta;
432
+ const targetPath = subpasta ? path.join(TAILWIND_SRC_PATH, subpasta) : TAILWIND_SRC_PATH;
433
+ if (!fs.existsSync(targetPath)) {
434
+ return {
435
+ content: [{ type: 'text', text: `❌ Pasta não encontrada: ${subpasta || 'src'}` }],
436
+ isError: true,
437
+ };
438
+ }
439
+ const tree = getDirectoryTree(targetPath);
440
+ return {
441
+ content: [
442
+ {
443
+ type: 'text',
444
+ text: `# 📁 Estrutura de ${subpasta || 'tailwindcss/packages/tailwindcss/src'}\n\n\`\`\`\n${tree}\`\`\``,
445
+ },
446
+ ],
447
+ };
448
+ }
449
+ case 'tailwind_ler_arquivo': {
450
+ const caminho = args.caminho;
451
+ const fullPath = path.join(TAILWIND_SRC_PATH, caminho);
452
+ if (!fs.existsSync(fullPath)) {
453
+ return {
454
+ content: [{ type: 'text', text: `❌ Arquivo não encontrado: ${caminho}` }],
455
+ isError: true,
456
+ };
457
+ }
458
+ const content = fs.readFileSync(fullPath, 'utf-8');
459
+ const ext = path.extname(caminho).slice(1) || 'typescript';
460
+ return {
461
+ content: [
462
+ {
463
+ type: 'text',
464
+ text: `# 📄 ${caminho}\n\n\`\`\`${ext}\n${content}\n\`\`\``,
465
+ },
466
+ ],
467
+ };
468
+ }
469
+ case 'tailwind_extrair_tipos': {
470
+ const { modulo, apenas_kind } = args;
471
+ const parser = new AstParser(TAILWIND_SRC_PATH);
472
+ let types;
473
+ if (modulo) {
474
+ types = parser.getTypesFromModule(modulo);
475
+ }
476
+ else {
477
+ types = parser.extractAllTypes();
478
+ }
479
+ if (apenas_kind) {
480
+ types = types.filter((t) => t.kind === apenas_kind);
481
+ }
482
+ const grouped = {};
483
+ for (const type of types) {
484
+ if (!grouped[type.module])
485
+ grouped[type.module] = [];
486
+ grouped[type.module].push(type);
487
+ }
488
+ let result = `# 📚 Tipos Exportados${modulo ? ` (${modulo})` : ''}${apenas_kind ? ` - ${CATEGORY_LABELS[apenas_kind]}` : ''}\n\n`;
489
+ result += `**Total:** ${types.length} declarações\n\n`;
490
+ for (const [mod, moduleTypes] of Object.entries(grouped)) {
491
+ result += `## 📁 ${mod}\n\n`;
492
+ for (const type of moduleTypes) {
493
+ result += formatExtractedType(type, false);
494
+ }
495
+ }
496
+ return {
497
+ content: [{ type: 'text', text: result }],
498
+ };
499
+ }
500
+ case 'tailwind_buscar_tipo': {
501
+ const nome = args.nome;
502
+ const parser = new AstParser(TAILWIND_SRC_PATH);
503
+ const found = parser.searchType(nome);
504
+ if (!found) {
505
+ const fuzzyResults = parser.fuzzySearch(nome, 5);
506
+ let suggestion = '';
507
+ if (fuzzyResults.length > 0) {
508
+ suggestion = '\n\n**Você quis dizer:**\n' + fuzzyResults.map((t) => `- \`${t.name}\` (${t.kind})`).join('\n');
509
+ }
510
+ return {
511
+ content: [
512
+ {
513
+ type: 'text',
514
+ text: `❌ Tipo "${nome}" não encontrado.${suggestion}`,
515
+ },
516
+ ],
517
+ isError: true,
518
+ };
519
+ }
520
+ return {
521
+ content: [{ type: 'text', text: formatExtractedType(found, true) }],
522
+ };
523
+ }
524
+ case 'tailwind_buscar_fuzzy': {
525
+ const { query, limite } = args;
526
+ const parser = new AstParser(TAILWIND_SRC_PATH);
527
+ const results = parser.fuzzySearch(query, limite || 20);
528
+ if (results.length === 0) {
529
+ return {
530
+ content: [{ type: 'text', text: `❌ Nenhum resultado encontrado para "${query}"` }],
531
+ isError: true,
532
+ };
533
+ }
534
+ let result = `# 🔍 Resultados para "${query}"\n\n`;
535
+ result += `**Encontrados:** ${results.length} tipos\n\n`;
536
+ for (const type of results) {
537
+ result += `- ${CATEGORY_EMOJI[type.kind]} **\`${type.name}\`** (${type.kind}) - \`${type.file}\`\n`;
538
+ if (type.docs)
539
+ result += ` > ${type.docs.substring(0, 100)}...\n`;
540
+ }
541
+ return {
542
+ content: [{ type: 'text', text: result }],
543
+ };
544
+ }
545
+ case 'tailwind_listar_exports': {
546
+ const parser = new AstParser(TAILWIND_SRC_PATH);
547
+ const types = parser.extractAllTypes();
548
+ const byModule = {};
549
+ for (const type of types) {
550
+ if (!byModule[type.module]) {
551
+ byModule[type.module] = {};
552
+ }
553
+ if (!byModule[type.module][type.kind]) {
554
+ byModule[type.module][type.kind] = [];
555
+ }
556
+ byModule[type.module][type.kind].push(type.name);
557
+ }
558
+ let result = '# 📚 Exports da Biblioteca Tailwind CSS\n\n';
559
+ result += `**Total:** ${types.length} declarações exportadas\n\n`;
560
+ for (const [module, kinds] of Object.entries(byModule)) {
561
+ const total = Object.values(kinds).flat().length;
562
+ result += `## 📁 ${module} (${total})\n\n`;
563
+ for (const [kind, names] of Object.entries(kinds)) {
564
+ result += `### ${CATEGORY_EMOJI[kind]} ${CATEGORY_LABELS[kind]} (${names.length})\n`;
565
+ for (const name of names.slice(0, 10)) {
566
+ result += `- \`${name}\`\n`;
567
+ }
568
+ if (names.length > 10) {
569
+ result += `- ... e mais ${names.length - 10}\n`;
570
+ }
571
+ result += '\n';
572
+ }
573
+ }
574
+ return {
575
+ content: [{ type: 'text', text: result }],
576
+ };
577
+ }
578
+ case 'tailwind_categorias': {
579
+ const { categoria, modulo } = args;
580
+ const parser = new AstParser(TAILWIND_SRC_PATH);
581
+ let types = parser.getTypesByKind(categoria);
582
+ if (modulo) {
583
+ types = types.filter((t) => t.module.toLowerCase() === modulo.toLowerCase());
584
+ }
585
+ let result = `# ${CATEGORY_EMOJI[categoria]} ${CATEGORY_LABELS[categoria]}\n\n`;
586
+ result += `**Total:** ${types.length}\n\n`;
587
+ for (const type of types) {
588
+ result += formatExtractedType(type, categoria === 'enum' || categoria === 'interface');
589
+ }
590
+ return {
591
+ content: [{ type: 'text', text: result }],
592
+ };
593
+ }
594
+ case 'tailwind_constantes': {
595
+ const { modulo } = args;
596
+ const parser = new AstParser(TAILWIND_SRC_PATH);
597
+ let constants = parser.getConstants();
598
+ if (modulo) {
599
+ constants = constants.filter((c) => c.module.toLowerCase() === modulo.toLowerCase());
600
+ }
601
+ let result = '# 📦 Constantes e Variáveis Exportadas\n\n';
602
+ result += `**Total:** ${constants.length}\n\n`;
603
+ const byModule = {};
604
+ for (const c of constants) {
605
+ if (!byModule[c.module])
606
+ byModule[c.module] = [];
607
+ byModule[c.module].push(c);
608
+ }
609
+ for (const [mod, vars] of Object.entries(byModule)) {
610
+ result += `## 📁 ${mod}\n\n`;
611
+ for (const v of vars) {
612
+ result += `### \`${v.name}\`\n`;
613
+ result += `**Tipo:** \`${v.signature.replace(`const ${v.name}: `, '')}\`\n`;
614
+ if (v.value) {
615
+ result += `**Valor:** \`${v.value}\`\n`;
616
+ }
617
+ result += '\n';
618
+ }
619
+ }
620
+ return {
621
+ content: [{ type: 'text', text: result }],
622
+ };
623
+ }
624
+ case 'tailwind_hierarquia': {
625
+ const { nome } = args;
626
+ const parser = new AstParser(TAILWIND_SRC_PATH);
627
+ const hierarchy = parser.getTypeHierarchy(nome);
628
+ if (!hierarchy) {
629
+ return {
630
+ content: [{ type: 'text', text: `❌ Tipo "${nome}" não encontrado.` }],
631
+ isError: true,
632
+ };
633
+ }
634
+ let result = `# 🌳 Hierarquia de \`${hierarchy.type.name}\`\n\n`;
635
+ result += formatExtractedType(hierarchy.type, false);
636
+ if (hierarchy.parents.length > 0) {
637
+ result += '## ⬆️ Herda de (Parents)\n\n';
638
+ for (const parent of hierarchy.parents) {
639
+ result += `- \`${parent}\`\n`;
640
+ }
641
+ result += '\n';
642
+ }
643
+ if (hierarchy.children.length > 0) {
644
+ result += '## ⬇️ Herdado por (Children)\n\n';
645
+ for (const child of hierarchy.children) {
646
+ result += `- \`${child}\`\n`;
647
+ }
648
+ result += '\n';
649
+ }
650
+ if (hierarchy.parents.length === 0 && hierarchy.children.length === 0) {
651
+ result += '*Este tipo não possui relacionamentos de herança.*\n';
652
+ }
653
+ return {
654
+ content: [{ type: 'text', text: result }],
655
+ };
656
+ }
657
+ case 'tailwind_estatisticas': {
658
+ const parser = new AstParser(TAILWIND_SRC_PATH);
659
+ const stats = parser.getStatistics();
660
+ return {
661
+ content: [{ type: 'text', text: formatStatistics(stats) }],
662
+ };
663
+ }
664
+ case 'tailwind_dependencias': {
665
+ const parser = new AstParser(TAILWIND_SRC_PATH);
666
+ const deps = parser.analyzeDependencies();
667
+ return {
668
+ content: [{ type: 'text', text: formatDependencies(deps) }],
669
+ };
670
+ }
671
+ case 'tailwind_enums': {
672
+ const parser = new AstParser(TAILWIND_SRC_PATH);
673
+ const enums = parser.getEnums();
674
+ let result = '# 🔢 Enumerações da Biblioteca\n\n';
675
+ result += `**Total:** ${enums.length}\n\n`;
676
+ for (const e of enums) {
677
+ result += `## \`${e.name}\`\n\n`;
678
+ result += `**Arquivo:** \`${e.file}\`\n\n`;
679
+ if (e.docs)
680
+ result += `> ${e.docs}\n\n`;
681
+ if (e.members && e.members.length > 0) {
682
+ result += '**Valores:**\n';
683
+ for (const member of e.members) {
684
+ result += `- \`${member}\`\n`;
685
+ }
686
+ }
687
+ result += '\n';
688
+ }
689
+ return {
690
+ content: [{ type: 'text', text: result }],
691
+ };
692
+ }
693
+ case 'tailwind_interfaces': {
694
+ const { modulo, detalhado } = args;
695
+ const parser = new AstParser(TAILWIND_SRC_PATH);
696
+ let interfaces = parser.getInterfaces();
697
+ if (modulo) {
698
+ interfaces = interfaces.filter((i) => i.module.toLowerCase() === modulo.toLowerCase());
699
+ }
700
+ let result = '# 📋 Interfaces da Biblioteca\n\n';
701
+ result += `**Total:** ${interfaces.length}\n\n`;
702
+ for (const iface of interfaces) {
703
+ result += formatExtractedType(iface, detalhado || false);
704
+ }
705
+ return {
706
+ content: [{ type: 'text', text: result }],
707
+ };
708
+ }
709
+ case 'tailwind_funcoes': {
710
+ const { modulo } = args;
711
+ const parser = new AstParser(TAILWIND_SRC_PATH);
712
+ let functions = parser.getFunctions();
713
+ if (modulo) {
714
+ functions = functions.filter((f) => f.module.toLowerCase() === modulo.toLowerCase());
715
+ }
716
+ let result = '# ⚡ Funções da Biblioteca\n\n';
717
+ result += `**Total:** ${functions.length}\n\n`;
718
+ const byModule = {};
719
+ for (const f of functions) {
720
+ if (!byModule[f.module])
721
+ byModule[f.module] = [];
722
+ byModule[f.module].push(f);
723
+ }
724
+ for (const [mod, funcs] of Object.entries(byModule)) {
725
+ result += `## 📁 ${mod}\n\n`;
726
+ for (const func of funcs) {
727
+ result += formatExtractedType(func, true);
728
+ }
729
+ }
730
+ return {
731
+ content: [{ type: 'text', text: result }],
732
+ };
733
+ }
734
+ case 'tailwind_integracoes': {
735
+ const { framework } = args;
736
+ const key = framework.toLowerCase();
737
+ const guides = {
738
+ vite: {
739
+ title: 'Vite (React/Vue/Svelte)',
740
+ v4: {
741
+ steps: [
742
+ 'Instale deps: npm install tailwindcss @tailwindcss/vite',
743
+ 'Configure o plugin no vite.config.ts',
744
+ 'Crie o CSS com @import "tailwindcss"',
745
+ 'Importe o CSS no entry (main.tsx/main.ts)',
746
+ ],
747
+ configSnippet: `// vite.config.ts
748
+ import tailwindcss from '@tailwindcss/vite'
749
+ import { defineConfig } from 'vite'
750
+
751
+ export default defineConfig({
752
+ plugins: [tailwindcss()]
753
+ })`,
754
+ cssSnippet: `/* app.css */
755
+ @import "tailwindcss";
756
+
757
+ @theme {
758
+ /* Customize theme variables */
759
+ --color-brand: oklch(0.72 0.11 221.19);
760
+ }`,
761
+ },
762
+ v3: {
763
+ steps: [
764
+ 'Instale deps: npm install -D tailwindcss postcss autoprefixer',
765
+ 'Gere config: npx tailwindcss init -p',
766
+ 'Configure content no tailwind.config.js',
767
+ 'Crie CSS com diretivas @tailwind',
768
+ ],
769
+ configSnippet: `// tailwind.config.js
770
+ module.exports = {
771
+ content: ['./index.html', './src/**/*.{js,ts,jsx,tsx,vue,svelte}'],
772
+ theme: { extend: {} },
773
+ plugins: [],
774
+ }`,
775
+ cssSnippet: `/* src/index.css */
776
+ @tailwind base;
777
+ @tailwind components;
778
+ @tailwind utilities;`,
779
+ },
780
+ contentGlob: './index.html, ./src/**/*.{js,ts,jsx,tsx,vue,svelte}',
781
+ },
782
+ next: {
783
+ title: 'Next.js (App Router)',
784
+ v4: {
785
+ steps: [
786
+ 'Instale deps: npm install tailwindcss @tailwindcss/postcss postcss',
787
+ 'Configure postcss.config.mjs',
788
+ 'Crie app/globals.css com @import "tailwindcss"',
789
+ 'Importe em app/layout.tsx',
790
+ ],
791
+ configSnippet: `// postcss.config.mjs
792
+ export default {
793
+ plugins: {
794
+ '@tailwindcss/postcss': {}
795
+ }
796
+ }`,
797
+ cssSnippet: `/* app/globals.css */
798
+ @import "tailwindcss";
799
+
800
+ @theme {
801
+ --color-primary: oklch(0.62 0.21 259.81);
802
+ }`,
803
+ },
804
+ v3: {
805
+ steps: [
806
+ 'Instale deps: npm install -D tailwindcss postcss autoprefixer',
807
+ 'Gere config: npx tailwindcss init -p',
808
+ 'Configure content no tailwind.config.js',
809
+ 'Crie globals.css com diretivas @tailwind',
810
+ ],
811
+ configSnippet: `// tailwind.config.js
812
+ module.exports = {
813
+ content: [
814
+ './app/**/*.{js,ts,jsx,tsx,mdx}',
815
+ './pages/**/*.{js,ts,jsx,tsx}',
816
+ './components/**/*.{js,ts,jsx,tsx}',
817
+ './src/**/*.{js,ts,jsx,tsx,mdx}',
818
+ ],
819
+ theme: { extend: {} },
820
+ plugins: [],
821
+ }`,
822
+ cssSnippet: `/* app/globals.css */
823
+ @tailwind base;
824
+ @tailwind components;
825
+ @tailwind utilities;`,
826
+ },
827
+ contentGlob: './app/**/*.{js,ts,jsx,tsx,mdx}, ./components/**/*.{js,ts,jsx,tsx}',
828
+ },
829
+ nuxt: {
830
+ title: 'Nuxt 3',
831
+ v4: {
832
+ steps: [
833
+ 'Instale deps: npm install tailwindcss @tailwindcss/postcss postcss',
834
+ 'Configure postcss no nuxt.config.ts',
835
+ 'Crie assets/css/main.css com @import "tailwindcss"',
836
+ 'Adicione o CSS ao nuxt.config.ts',
837
+ ],
838
+ configSnippet: `// nuxt.config.ts
839
+ export default defineNuxtConfig({
840
+ css: ['~/assets/css/main.css'],
841
+ postcss: {
842
+ plugins: {
843
+ '@tailwindcss/postcss': {}
844
+ }
845
+ }
846
+ })`,
847
+ cssSnippet: `/* assets/css/main.css */
848
+ @import "tailwindcss";
849
+
850
+ @theme {
851
+ --color-brand: oklch(0.69 0.17 162.48);
852
+ }`,
853
+ },
854
+ v3: {
855
+ steps: [
856
+ 'Instale deps: npm install -D tailwindcss postcss autoprefixer',
857
+ 'Gere config: npx tailwindcss init -p',
858
+ 'Configure content e adicione CSS ao nuxt.config.ts',
859
+ ],
860
+ configSnippet: `// tailwind.config.js
861
+ module.exports = {
862
+ content: [
863
+ './components/**/*.{vue,js,ts}',
864
+ './layouts/**/*.vue',
865
+ './pages/**/*.vue',
866
+ './app.vue',
867
+ './plugins/**/*.{js,ts}',
868
+ ],
869
+ theme: { extend: {} },
870
+ plugins: [],
871
+ }`,
872
+ cssSnippet: `/* assets/css/tailwind.css */
873
+ @tailwind base;
874
+ @tailwind components;
875
+ @tailwind utilities;`,
876
+ },
877
+ contentGlob: './components/**/*.{vue,js,ts}, ./pages/**/*.vue, ./app.vue',
878
+ },
879
+ sveltekit: {
880
+ title: 'SvelteKit',
881
+ v4: {
882
+ steps: [
883
+ 'Instale deps: npm install tailwindcss @tailwindcss/vite',
884
+ 'Configure o plugin no vite.config.ts',
885
+ 'Crie src/app.css com @import "tailwindcss"',
886
+ 'Importe em src/routes/+layout.svelte',
887
+ ],
888
+ configSnippet: `// vite.config.ts
889
+ import { sveltekit } from '@sveltejs/kit/vite'
890
+ import tailwindcss from '@tailwindcss/vite'
891
+ import { defineConfig } from 'vite'
892
+
893
+ export default defineConfig({
894
+ plugins: [tailwindcss(), sveltekit()]
895
+ })`,
896
+ cssSnippet: `/* src/app.css */
897
+ @import "tailwindcss";`,
898
+ },
899
+ v3: {
900
+ steps: [
901
+ 'Instale deps: npm install -D tailwindcss postcss autoprefixer',
902
+ 'Gere config: npx tailwindcss init -p',
903
+ 'Crie src/app.css e importe em +layout.svelte',
904
+ ],
905
+ configSnippet: `// tailwind.config.js
906
+ module.exports = {
907
+ content: ['./src/**/*.{html,js,svelte,ts}'],
908
+ theme: { extend: {} },
909
+ plugins: [],
910
+ }`,
911
+ cssSnippet: `/* src/app.css */
912
+ @tailwind base;
913
+ @tailwind components;
914
+ @tailwind utilities;`,
915
+ },
916
+ contentGlob: './src/**/*.{html,js,svelte,ts}',
917
+ },
918
+ astro: {
919
+ title: 'Astro',
920
+ v4: {
921
+ steps: [
922
+ 'Instale deps: npm install tailwindcss @tailwindcss/vite',
923
+ 'Configure o plugin no astro.config.mjs',
924
+ 'Crie src/styles/global.css com @import "tailwindcss"',
925
+ 'Importe em layouts/Layout.astro',
926
+ ],
927
+ configSnippet: `// astro.config.mjs
928
+ import { defineConfig } from 'astro/config'
929
+ import tailwindcss from '@tailwindcss/vite'
930
+
931
+ export default defineConfig({
932
+ vite: {
933
+ plugins: [tailwindcss()]
934
+ }
935
+ })`,
936
+ cssSnippet: `/* src/styles/global.css */
937
+ @import "tailwindcss";`,
938
+ },
939
+ v3: {
940
+ steps: [
941
+ 'Use: npx astro add tailwind (recomendado)',
942
+ 'Ou manual: npm install -D tailwindcss @astrojs/tailwind',
943
+ ],
944
+ configSnippet: `// tailwind.config.js
945
+ module.exports = {
946
+ content: ['./src/**/*.{astro,html,js,jsx,ts,tsx,vue,svelte}'],
947
+ theme: { extend: {} },
948
+ plugins: [],
949
+ }`,
950
+ cssSnippet: `/* src/styles/global.css */
951
+ @tailwind base;
952
+ @tailwind components;
953
+ @tailwind utilities;`,
954
+ },
955
+ contentGlob: './src/**/*.{astro,html,js,jsx,ts,tsx,vue,svelte}',
956
+ },
957
+ remix: {
958
+ title: 'Remix',
959
+ v4: {
960
+ steps: [
961
+ 'Instale deps: npm install tailwindcss @tailwindcss/vite',
962
+ 'Configure o plugin no vite.config.ts',
963
+ 'Crie app/tailwind.css com @import "tailwindcss"',
964
+ 'Importe em app/root.tsx via links()',
965
+ ],
966
+ configSnippet: `// vite.config.ts
967
+ import { vitePlugin as remix } from '@remix-run/dev'
968
+ import tailwindcss from '@tailwindcss/vite'
969
+ import { defineConfig } from 'vite'
970
+
971
+ export default defineConfig({
972
+ plugins: [tailwindcss(), remix()]
973
+ })`,
974
+ cssSnippet: `/* app/tailwind.css */
975
+ @import "tailwindcss";`,
976
+ },
977
+ v3: {
978
+ steps: [
979
+ 'Instale deps: npm install -D tailwindcss postcss autoprefixer',
980
+ 'Gere config: npx tailwindcss init -p',
981
+ 'Crie app/tailwind.css e importe em root.tsx',
982
+ ],
983
+ configSnippet: `// tailwind.config.js
984
+ module.exports = {
985
+ content: ['./app/**/*.{ts,tsx,js,jsx}'],
986
+ theme: { extend: {} },
987
+ plugins: [],
988
+ }`,
989
+ cssSnippet: `/* app/tailwind.css */
990
+ @tailwind base;
991
+ @tailwind components;
992
+ @tailwind utilities;`,
993
+ },
994
+ contentGlob: './app/**/*.{ts,tsx,js,jsx}',
995
+ },
996
+ vue: {
997
+ title: 'Vue 3 (Vite)',
998
+ v4: {
999
+ steps: [
1000
+ 'Instale deps: npm install tailwindcss @tailwindcss/vite',
1001
+ 'Configure o plugin no vite.config.ts',
1002
+ 'Crie src/assets/main.css com @import "tailwindcss"',
1003
+ 'Importe em src/main.ts',
1004
+ ],
1005
+ configSnippet: `// vite.config.ts
1006
+ import vue from '@vitejs/plugin-vue'
1007
+ import tailwindcss from '@tailwindcss/vite'
1008
+ import { defineConfig } from 'vite'
1009
+
1010
+ export default defineConfig({
1011
+ plugins: [vue(), tailwindcss()]
1012
+ })`,
1013
+ cssSnippet: `/* src/assets/main.css */
1014
+ @import "tailwindcss";`,
1015
+ },
1016
+ v3: {
1017
+ steps: [
1018
+ 'Instale deps: npm install -D tailwindcss postcss autoprefixer',
1019
+ 'Gere config: npx tailwindcss init -p',
1020
+ 'Crie src/assets/tailwind.css e importe em main.ts',
1021
+ ],
1022
+ configSnippet: `// tailwind.config.js
1023
+ module.exports = {
1024
+ content: ['./index.html', './src/**/*.{vue,js,ts,jsx,tsx}'],
1025
+ theme: { extend: {} },
1026
+ plugins: [],
1027
+ }`,
1028
+ cssSnippet: `/* src/assets/tailwind.css */
1029
+ @tailwind base;
1030
+ @tailwind components;
1031
+ @tailwind utilities;`,
1032
+ },
1033
+ contentGlob: './index.html, ./src/**/*.{vue,js,ts,jsx,tsx}',
1034
+ },
1035
+ react: {
1036
+ title: 'React (Vite)',
1037
+ v4: {
1038
+ steps: [
1039
+ 'Instale deps: npm install tailwindcss @tailwindcss/vite',
1040
+ 'Configure o plugin no vite.config.ts',
1041
+ 'Crie src/index.css com @import "tailwindcss"',
1042
+ 'Importe em src/main.tsx',
1043
+ ],
1044
+ configSnippet: `// vite.config.ts
1045
+ import react from '@vitejs/plugin-react'
1046
+ import tailwindcss from '@tailwindcss/vite'
1047
+ import { defineConfig } from 'vite'
1048
+
1049
+ export default defineConfig({
1050
+ plugins: [react(), tailwindcss()]
1051
+ })`,
1052
+ cssSnippet: `/* src/index.css */
1053
+ @import "tailwindcss";`,
1054
+ },
1055
+ v3: {
1056
+ steps: [
1057
+ 'Instale deps: npm install -D tailwindcss postcss autoprefixer',
1058
+ 'Gere config: npx tailwindcss init -p',
1059
+ 'Crie src/index.css e importe em main.tsx/index.tsx',
1060
+ ],
1061
+ configSnippet: `// tailwind.config.js
1062
+ module.exports = {
1063
+ content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
1064
+ theme: { extend: {} },
1065
+ plugins: [],
1066
+ }`,
1067
+ cssSnippet: `/* src/index.css */
1068
+ @tailwind base;
1069
+ @tailwind components;
1070
+ @tailwind utilities;`,
1071
+ },
1072
+ contentGlob: './index.html, ./src/**/*.{js,ts,jsx,tsx}',
1073
+ },
1074
+ postcss: {
1075
+ title: 'PostCSS (Universal)',
1076
+ v4: {
1077
+ steps: [
1078
+ 'Instale deps: npm install tailwindcss @tailwindcss/postcss postcss',
1079
+ 'Configure postcss.config.js',
1080
+ 'Crie CSS com @import "tailwindcss"',
1081
+ ],
1082
+ configSnippet: `// postcss.config.js
1083
+ export default {
1084
+ plugins: {
1085
+ '@tailwindcss/postcss': {}
1086
+ }
1087
+ }`,
1088
+ cssSnippet: `/* styles.css */
1089
+ @import "tailwindcss";`,
1090
+ },
1091
+ v3: {
1092
+ steps: [
1093
+ 'Instale deps: npm install -D tailwindcss postcss autoprefixer',
1094
+ 'Configure postcss.config.js',
1095
+ 'Crie CSS com diretivas @tailwind',
1096
+ ],
1097
+ configSnippet: `// postcss.config.js
1098
+ module.exports = {
1099
+ plugins: {
1100
+ tailwindcss: {},
1101
+ autoprefixer: {},
1102
+ }
1103
+ }`,
1104
+ cssSnippet: `/* styles.css */
1105
+ @tailwind base;
1106
+ @tailwind components;
1107
+ @tailwind utilities;`,
1108
+ },
1109
+ contentGlob: './src/**/*.{html,js,ts,jsx,tsx}',
1110
+ },
1111
+ cli: {
1112
+ title: 'CLI (Standalone)',
1113
+ v4: {
1114
+ steps: [
1115
+ 'Instale: npm install tailwindcss @tailwindcss/cli',
1116
+ 'Execute: npx @tailwindcss/cli -i input.css -o output.css --watch',
1117
+ ],
1118
+ configSnippet: `# Comando para build
1119
+ npx @tailwindcss/cli -i input.css -o output.css
1120
+
1121
+ # Comando para watch
1122
+ npx @tailwindcss/cli -i input.css -o output.css --watch
1123
+
1124
+ # Minificado para produção
1125
+ npx @tailwindcss/cli -i input.css -o output.css --minify`,
1126
+ cssSnippet: `/* input.css */
1127
+ @import "tailwindcss";`,
1128
+ },
1129
+ v3: {
1130
+ steps: [
1131
+ 'Instale: npm install -D tailwindcss',
1132
+ 'Gere config: npx tailwindcss init',
1133
+ 'Execute: npx tailwindcss -i input.css -o output.css --watch',
1134
+ ],
1135
+ configSnippet: `# Comando para watch
1136
+ npx tailwindcss -i ./src/input.css -o ./dist/output.css --watch
1137
+
1138
+ # Minificado para produção
1139
+ npx tailwindcss -i ./src/input.css -o ./dist/output.css --minify`,
1140
+ cssSnippet: `/* input.css */
1141
+ @tailwind base;
1142
+ @tailwind components;
1143
+ @tailwind utilities;`,
1144
+ },
1145
+ contentGlob: './src/**/*.{html,js}',
1146
+ },
1147
+ };
1148
+ const guide = guides[key];
1149
+ if (!guide) {
1150
+ const available = Object.keys(guides).join(', ');
1151
+ return {
1152
+ content: [{ type: 'text', text: `❌ Framework não suportado: ${framework}\n\nFrameworks disponíveis: ${available}` }],
1153
+ isError: true,
1154
+ };
1155
+ }
1156
+ let result = `# 🚀 Integração Tailwind CSS + ${guide.title}\n\n`;
1157
+ result += '---\n\n';
1158
+ result += '## ⚡ Tailwind v4 (Recomendado)\n\n';
1159
+ result += '**Passos:**\n';
1160
+ for (let i = 0; i < guide.v4.steps.length; i++) {
1161
+ result += `${i + 1}. ${guide.v4.steps[i]}\n`;
1162
+ }
1163
+ result += '\n**Configuração:**\n```ts\n' + guide.v4.configSnippet + '\n```\n\n';
1164
+ result += '**CSS:**\n```css\n' + guide.v4.cssSnippet + '\n```\n\n';
1165
+ result += '---\n\n';
1166
+ result += '## 📦 Tailwind v3 (Legado)\n\n';
1167
+ result += '**Passos:**\n';
1168
+ for (let i = 0; i < guide.v3.steps.length; i++) {
1169
+ result += `${i + 1}. ${guide.v3.steps[i]}\n`;
1170
+ }
1171
+ result += '\n**Configuração:**\n```js\n' + guide.v3.configSnippet + '\n```\n\n';
1172
+ result += '**CSS:**\n```css\n' + guide.v3.cssSnippet + '\n```\n\n';
1173
+ result += '---\n\n';
1174
+ result += `**Content glob recomendado:** \`${guide.contentGlob}\`\n`;
1175
+ return {
1176
+ content: [{ type: 'text', text: result }],
1177
+ };
1178
+ }
1179
+ case 'tailwind_check_updates': {
1180
+ const updateInfo = await checkForUpdates();
1181
+ let result = '# 🔍 Verificação de Atualizações\n\n';
1182
+ if (updateInfo.hasUpdate) {
1183
+ result += '⚠️ **Atualização disponível!**\n\n';
1184
+ result += `**Commit local:** \`${updateInfo.currentSha?.substring(0, 7) || 'N/A'}\`\n`;
1185
+ result += `**Commit remoto:** \`${updateInfo.latestSha?.substring(0, 7) || 'N/A'}\`\n\n`;
1186
+ if (updateInfo.latestCommit) {
1187
+ result += `**Último commit:**\n`;
1188
+ result += `- Mensagem: ${updateInfo.latestCommit.message}\n`;
1189
+ result += `- Autor: ${updateInfo.latestCommit.author}\n`;
1190
+ result += `- Data: ${updateInfo.latestCommit.date}\n\n`;
1191
+ }
1192
+ result += '> Use `tailwind_update` para atualizar o repositório.\n';
1193
+ }
1194
+ else {
1195
+ result += '✅ **Repositório está atualizado!**\n\n';
1196
+ result += `**Commit atual:** \`${updateInfo.currentSha?.substring(0, 7) || 'N/A'}\`\n`;
1197
+ }
1198
+ return {
1199
+ content: [{ type: 'text', text: result }],
1200
+ };
1201
+ }
1202
+ case 'tailwind_update': {
1203
+ const updateResult = await checkAndUpdate();
1204
+ let result = '# 🔄 Atualização do Repositório\n\n';
1205
+ if (updateResult.updated) {
1206
+ result += '✅ **Repositório atualizado com sucesso!**\n\n';
1207
+ if (updateResult.previousSha) {
1208
+ result += `**De:** \`${updateResult.previousSha.substring(0, 7)}\`\n`;
1209
+ }
1210
+ result += `**Para:** \`${updateResult.currentSha?.substring(0, 7) || 'N/A'}\`\n\n`;
1211
+ if (updateResult.commitMessage) {
1212
+ result += `**Commit:** ${updateResult.commitMessage}\n`;
1213
+ }
1214
+ if (updateResult.commitDate) {
1215
+ result += `**Data:** ${updateResult.commitDate}\n`;
1216
+ }
1217
+ result += '\n> ⚡ O contexto da biblioteca foi atualizado automaticamente.\n';
1218
+ }
1219
+ else if (updateResult.error) {
1220
+ result += '❌ **Erro ao atualizar:**\n\n';
1221
+ result += `\`\`\`\n${updateResult.error}\n\`\`\`\n`;
1222
+ }
1223
+ else {
1224
+ result += '✅ **Já está na versão mais recente!**\n\n';
1225
+ result += `**Commit atual:** \`${updateResult.currentSha?.substring(0, 7) || 'N/A'}\`\n`;
1226
+ }
1227
+ return {
1228
+ content: [{ type: 'text', text: result }],
1229
+ };
1230
+ }
1231
+ case 'tailwind_status': {
1232
+ const status = await getRepositoryStatus();
1233
+ let result = '# 📊 Status do Repositório Tailwind CSS\n\n';
1234
+ result += `**Repositório válido:** ${status.isValid ? '✅ Sim' : '❌ Não'}\n`;
1235
+ result += `**Caminho:** \`${status.repoPath}\`\n\n`;
1236
+ result += `**Commit local:** \`${status.localSha?.substring(0, 7) || 'N/A'}\`\n`;
1237
+ result += `**Commit remoto:** \`${status.remoteSha?.substring(0, 7) || 'N/A'}\`\n\n`;
1238
+ if (status.hasUpdates) {
1239
+ result += '⚠️ **Há atualizações disponíveis!**\n\n';
1240
+ result += '> Use `tailwind_update` para atualizar.\n';
1241
+ }
1242
+ else {
1243
+ result += '✅ **Repositório está sincronizado com o GitHub.**\n';
1244
+ }
1245
+ result += `\n**Última verificação:** ${status.lastCheck}\n`;
1246
+ return {
1247
+ content: [{ type: 'text', text: result }],
1248
+ };
1249
+ }
1250
+ default:
1251
+ return {
1252
+ content: [{ type: 'text', text: `❌ Ferramenta desconhecida: ${name}` }],
1253
+ isError: true,
1254
+ };
1255
+ }
1256
+ }
1257
+ catch (error) {
1258
+ return {
1259
+ content: [
1260
+ {
1261
+ type: 'text',
1262
+ text: `❌ Erro: ${error instanceof Error ? error.message : String(error)}`,
1263
+ },
1264
+ ],
1265
+ isError: true,
1266
+ };
1267
+ }
1268
+ });
1269
+ mcpServer.server.setRequestHandler(ListResourcesRequestSchema, async () => {
1270
+ return {
1271
+ resources: [
1272
+ {
1273
+ uri: 'tailwind://readme',
1274
+ name: 'Tailwind CSS README',
1275
+ description: 'Documentação principal da biblioteca Tailwind CSS',
1276
+ mimeType: 'text/markdown',
1277
+ },
1278
+ {
1279
+ uri: 'tailwind://types',
1280
+ name: 'Types Index',
1281
+ description: 'Tipos principais expostos pelo Tailwind',
1282
+ mimeType: 'text/markdown',
1283
+ },
1284
+ {
1285
+ uri: 'tailwind://statistics',
1286
+ name: 'Library Statistics',
1287
+ description: 'Estatísticas completas da biblioteca',
1288
+ mimeType: 'text/markdown',
1289
+ },
1290
+ ],
1291
+ };
1292
+ });
1293
+ mcpServer.server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
1294
+ const uri = request.params.uri;
1295
+ if (uri === 'tailwind://readme') {
1296
+ const readmePath = path.join(TAILWIND_SRC_PATH, '..', 'README.md');
1297
+ if (fs.existsSync(readmePath)) {
1298
+ const content = fs.readFileSync(readmePath, 'utf-8');
1299
+ return { contents: [{ uri, mimeType: 'text/markdown', text: content }] };
1300
+ }
1301
+ }
1302
+ if (uri === 'tailwind://types') {
1303
+ const indexPath = path.join(TAILWIND_SRC_PATH, 'types.ts');
1304
+ if (fs.existsSync(indexPath)) {
1305
+ const content = fs.readFileSync(indexPath, 'utf-8');
1306
+ return {
1307
+ contents: [
1308
+ {
1309
+ uri,
1310
+ mimeType: 'text/markdown',
1311
+ text: `# Types Index\n\n\`\`\`typescript\n${content}\n\`\`\``,
1312
+ },
1313
+ ],
1314
+ };
1315
+ }
1316
+ }
1317
+ if (uri === 'tailwind://statistics') {
1318
+ const parser = new AstParser(TAILWIND_SRC_PATH);
1319
+ const stats = parser.getStatistics();
1320
+ return {
1321
+ contents: [
1322
+ {
1323
+ uri,
1324
+ mimeType: 'text/markdown',
1325
+ text: formatStatistics(stats),
1326
+ },
1327
+ ],
1328
+ };
1329
+ }
1330
+ return { contents: [{ uri, mimeType: 'text/plain', text: 'Resource not found' }] };
1331
+ });
1332
+ const AUTO_UPDATE_INTERVAL = parseInt(process.env.AUTO_UPDATE_INTERVAL || '3600000', 10);
1333
+ const AUTO_UPDATE_ENABLED = process.env.AUTO_UPDATE_ENABLED !== 'false';
1334
+ async function main() {
1335
+ const repoResult = await ensureRepository();
1336
+ if (!repoResult.success) {
1337
+ console.error(`❌ ${repoResult.error}`);
1338
+ process.exit(1);
1339
+ }
1340
+ TAILWIND_SRC_PATH = repoResult.path;
1341
+ console.error(`📁 Usando Tailwind CSS: ${TAILWIND_SRC_PATH}`);
1342
+ const transport = new StdioServerTransport();
1343
+ await mcpServer.connect(transport);
1344
+ console.error('MCP Tailwind CSS server v2.0.0 running on stdio');
1345
+ if (AUTO_UPDATE_ENABLED) {
1346
+ const initialCheck = await checkForUpdates();
1347
+ if (initialCheck.hasUpdate) {
1348
+ console.error(`⚠️ Atualização disponível: ${initialCheck.latestCommit?.message}`);
1349
+ }
1350
+ scheduleUpdateCheck(AUTO_UPDATE_INTERVAL);
1351
+ }
1352
+ }
1353
+ main().catch((error) => {
1354
+ console.error('Fatal error:', error);
1355
+ process.exit(1);
1356
+ });
1357
+ //# sourceMappingURL=index.js.map