@justmpm/ai-tool 0.8.2 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +47 -1
- package/dist/chunk-CACALWH5.js +145 -0
- package/dist/{chunk-OMEBMR2V.js → chunk-NVJXCSJF.js} +652 -480
- package/dist/cli.js +16 -2
- package/dist/index.d.ts +51 -3
- package/dist/index.js +1 -1
- package/dist/server-OMKVOYK7.js +511 -0
- package/package.json +4 -3
- package/dist/server-JLK3OH5F.js +0 -537
package/dist/cli.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
describe
|
|
4
|
+
} from "./chunk-CACALWH5.js";
|
|
2
5
|
import {
|
|
3
6
|
VERSION,
|
|
4
7
|
area,
|
|
@@ -13,7 +16,7 @@ import {
|
|
|
13
16
|
impact,
|
|
14
17
|
map,
|
|
15
18
|
suggest
|
|
16
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-NVJXCSJF.js";
|
|
17
20
|
|
|
18
21
|
// src/cli.ts
|
|
19
22
|
import { resolve } from "path";
|
|
@@ -30,6 +33,7 @@ COMANDOS:
|
|
|
30
33
|
context <arquivo> Extrai assinaturas de um arquivo (funcoes, tipos)
|
|
31
34
|
context --area=<nome> Contexto consolidado de toda uma area
|
|
32
35
|
find <termo> Busca simbolos no codigo (funcoes, tipos, etc)
|
|
36
|
+
describe <termo> Busca areas por descricao em linguagem natural
|
|
33
37
|
|
|
34
38
|
AREAS:
|
|
35
39
|
areas Lista todas as areas/dominios do projeto
|
|
@@ -83,6 +87,7 @@ EXEMPLOS:
|
|
|
83
87
|
ai-tool find useAuth # Busca definicao e usos
|
|
84
88
|
ai-tool find User --type=type # Busca apenas tipos
|
|
85
89
|
ai-tool find login --area=auth # Busca na area auth
|
|
90
|
+
ai-tool describe cache # Busca areas por descricao
|
|
86
91
|
ai-tool areas
|
|
87
92
|
ai-tool area auth
|
|
88
93
|
ai-tool area auth --type=hook
|
|
@@ -108,7 +113,7 @@ async function main() {
|
|
|
108
113
|
}
|
|
109
114
|
}
|
|
110
115
|
if (flags.mcp) {
|
|
111
|
-
const { startMcpServer } = await import("./server-
|
|
116
|
+
const { startMcpServer } = await import("./server-OMKVOYK7.js");
|
|
112
117
|
await startMcpServer();
|
|
113
118
|
return;
|
|
114
119
|
}
|
|
@@ -222,6 +227,15 @@ async function main() {
|
|
|
222
227
|
trigger: flags.trigger
|
|
223
228
|
});
|
|
224
229
|
break;
|
|
230
|
+
case "describe":
|
|
231
|
+
if (!target) {
|
|
232
|
+
console.error("\u274C Erro: termo de busca \xE9 obrigat\xF3rio para o comando describe");
|
|
233
|
+
console.error(" Exemplo: ai-tool describe cache");
|
|
234
|
+
console.error(" Exemplo: ai-tool describe login");
|
|
235
|
+
process.exit(1);
|
|
236
|
+
}
|
|
237
|
+
result = await describe(target, { format, cwd });
|
|
238
|
+
break;
|
|
225
239
|
default:
|
|
226
240
|
console.error(`\u274C Comando desconhecido: ${command}`);
|
|
227
241
|
console.error(" Use 'ai-tool --help' para ver comandos dispon\xEDveis.");
|
package/dist/index.d.ts
CHANGED
|
@@ -103,6 +103,16 @@ interface ImpactResult {
|
|
|
103
103
|
};
|
|
104
104
|
risks: RiskInfo[];
|
|
105
105
|
suggestions: string[];
|
|
106
|
+
gitHistory?: {
|
|
107
|
+
hasGitRepo: boolean;
|
|
108
|
+
recentCommits: Array<{
|
|
109
|
+
hash: string;
|
|
110
|
+
shortHash: string;
|
|
111
|
+
message: string;
|
|
112
|
+
date: string;
|
|
113
|
+
author: string;
|
|
114
|
+
}>;
|
|
115
|
+
};
|
|
106
116
|
}
|
|
107
117
|
interface SuggestOptions extends CommandOptions {
|
|
108
118
|
limit?: number;
|
|
@@ -120,6 +130,7 @@ interface SuggestResult {
|
|
|
120
130
|
target: string;
|
|
121
131
|
category: FileCategory;
|
|
122
132
|
suggestions: Suggestion[];
|
|
133
|
+
testSuggestions: string[];
|
|
123
134
|
}
|
|
124
135
|
interface ContextOptions extends CommandOptions {
|
|
125
136
|
depth?: number;
|
|
@@ -471,62 +482,99 @@ interface FindResult {
|
|
|
471
482
|
declare function find(query: string, options?: FindOptions): Promise<string>;
|
|
472
483
|
|
|
473
484
|
/**
|
|
474
|
-
*
|
|
485
|
+
* Detecção de Triggers Firebase
|
|
475
486
|
*
|
|
476
|
-
*
|
|
477
|
-
*
|
|
487
|
+
* Identifica e extrai informações de Cloud Functions v2 do Firebase
|
|
488
|
+
* (onCall, onDocumentCreated, onSchedule, etc) durante a indexação do projeto.
|
|
478
489
|
*/
|
|
479
490
|
|
|
480
491
|
/**
|
|
481
492
|
* Metadados de um trigger Firebase
|
|
482
493
|
*/
|
|
483
494
|
interface TriggerInfo {
|
|
495
|
+
/** Tipo do trigger (ex: "onDocumentCreated", "onCall") */
|
|
484
496
|
triggerType: string;
|
|
497
|
+
/** Path para Firestore/RTDB (ex: "users/{userId}") */
|
|
485
498
|
triggerPath?: string;
|
|
499
|
+
/** Schedule expression para onSchedule (ex: "every 5 minutes") */
|
|
486
500
|
triggerSchedule?: string;
|
|
487
501
|
}
|
|
502
|
+
|
|
503
|
+
/**
|
|
504
|
+
* Cache de Símbolos do Projeto
|
|
505
|
+
*
|
|
506
|
+
* Indexa todos os arquivos do projeto e extrai símbolos
|
|
507
|
+
* (funções, tipos, interfaces, enums, componentes, hooks, triggers Firebase)
|
|
508
|
+
*
|
|
509
|
+
* O índice resultante pode ser cacheado e reutilizado pelos comandos find e context.
|
|
510
|
+
*/
|
|
511
|
+
|
|
488
512
|
/**
|
|
489
513
|
* Informação de um símbolo (função, tipo, constante, etc)
|
|
490
514
|
*/
|
|
491
515
|
interface SymbolInfo {
|
|
516
|
+
/** Nome do símbolo */
|
|
492
517
|
name: string;
|
|
518
|
+
/** Caminho do arquivo relativo ao projeto */
|
|
493
519
|
file: string;
|
|
520
|
+
/** Número da linha onde o símbolo está definido */
|
|
494
521
|
line: number;
|
|
522
|
+
/** Tipo do símbolo */
|
|
495
523
|
kind: "function" | "type" | "interface" | "enum" | "const" | "component" | "hook" | "trigger";
|
|
524
|
+
/** Assinatura do símbolo */
|
|
496
525
|
signature: string;
|
|
526
|
+
/** Se o símbolo é exportado */
|
|
497
527
|
isExported: boolean;
|
|
528
|
+
/** Parâmetros da função (se aplicável) */
|
|
498
529
|
params?: string[];
|
|
530
|
+
/** Tipo de retorno da função (se aplicável) */
|
|
499
531
|
returnType?: string;
|
|
532
|
+
/** Definição completa (para tipos, interfaces, enums) */
|
|
500
533
|
definition?: string;
|
|
534
|
+
/** Metadados específicos para triggers Firebase */
|
|
501
535
|
triggerInfo?: TriggerInfo;
|
|
502
536
|
}
|
|
503
537
|
/**
|
|
504
538
|
* Informação de import
|
|
505
539
|
*/
|
|
506
540
|
interface ImportInfo {
|
|
541
|
+
/** Caminho do módulo importado */
|
|
507
542
|
source: string;
|
|
543
|
+
/** Especificadores importados */
|
|
508
544
|
specifiers: string[];
|
|
545
|
+
/** Se é um import type-only */
|
|
509
546
|
isTypeOnly: boolean;
|
|
510
547
|
}
|
|
511
548
|
/**
|
|
512
549
|
* Dados extraídos de um arquivo
|
|
513
550
|
*/
|
|
514
551
|
interface FileSymbols {
|
|
552
|
+
/** Caminho do arquivo relativo ao projeto */
|
|
515
553
|
path: string;
|
|
554
|
+
/** Categoria do arquivo (component, page, hook, etc) */
|
|
516
555
|
category: FileCategory;
|
|
556
|
+
/** Lista de símbolos encontrados no arquivo */
|
|
517
557
|
symbols: SymbolInfo[];
|
|
558
|
+
/** Lista de imports do arquivo */
|
|
518
559
|
imports: ImportInfo[];
|
|
560
|
+
/** Lista de exports do arquivo */
|
|
519
561
|
exports: string[];
|
|
520
562
|
}
|
|
521
563
|
/**
|
|
522
564
|
* Índice completo do projeto
|
|
523
565
|
*/
|
|
524
566
|
interface ProjectIndex {
|
|
567
|
+
/** Versão do formato do índice */
|
|
525
568
|
version: string;
|
|
569
|
+
/** Timestamp de quando o índice foi criado */
|
|
526
570
|
timestamp: string;
|
|
571
|
+
/** Mapa de caminho → dados do arquivo */
|
|
527
572
|
files: Record<string, FileSymbols>;
|
|
573
|
+
/** Índice para busca rápida por nome do símbolo */
|
|
528
574
|
symbolsByName: Record<string, SymbolInfo[]>;
|
|
575
|
+
/** Número total de arquivos indexados */
|
|
529
576
|
fileCount: number;
|
|
577
|
+
/** Número total de símbolos encontrados */
|
|
530
578
|
symbolCount: number;
|
|
531
579
|
}
|
|
532
580
|
|
package/dist/index.js
CHANGED
|
@@ -0,0 +1,511 @@
|
|
|
1
|
+
import {
|
|
2
|
+
describe
|
|
3
|
+
} from "./chunk-CACALWH5.js";
|
|
4
|
+
import {
|
|
5
|
+
VERSION,
|
|
6
|
+
area,
|
|
7
|
+
areaContext,
|
|
8
|
+
areas,
|
|
9
|
+
areasInit,
|
|
10
|
+
context,
|
|
11
|
+
dead,
|
|
12
|
+
find,
|
|
13
|
+
functions,
|
|
14
|
+
impact,
|
|
15
|
+
map,
|
|
16
|
+
suggest
|
|
17
|
+
} from "./chunk-NVJXCSJF.js";
|
|
18
|
+
|
|
19
|
+
// src/mcp/server.ts
|
|
20
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
21
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
22
|
+
|
|
23
|
+
// src/mcp/tools.ts
|
|
24
|
+
import { z } from "zod";
|
|
25
|
+
function registerAllTools(server2) {
|
|
26
|
+
server2.registerTool(
|
|
27
|
+
"aitool_project_map",
|
|
28
|
+
{
|
|
29
|
+
title: "Project Map",
|
|
30
|
+
description: `Mapeia projeto e retorna resumo: contagens por categoria, areas detectadas, alertas.
|
|
31
|
+
Use no inicio da sessao. Para detalhes: area_detail, file_context, suggest_reads.
|
|
32
|
+
|
|
33
|
+
Parametros:
|
|
34
|
+
- format: text (legivel) ou json (estruturado)
|
|
35
|
+
- cwd: Diretorio do projeto a analisar`,
|
|
36
|
+
inputSchema: {
|
|
37
|
+
format: z.enum(["text", "json"]).default("text").describe("Formato de saida: text (legivel) ou json (estruturado)"),
|
|
38
|
+
cwd: z.string().optional().describe("Diretorio do projeto a analisar")
|
|
39
|
+
},
|
|
40
|
+
annotations: {
|
|
41
|
+
title: "Project Map",
|
|
42
|
+
readOnlyHint: true,
|
|
43
|
+
destructiveHint: false,
|
|
44
|
+
idempotentHint: true,
|
|
45
|
+
openWorldHint: false
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
async (params) => {
|
|
49
|
+
try {
|
|
50
|
+
const result = await map({
|
|
51
|
+
format: params.format,
|
|
52
|
+
cwd: params.cwd,
|
|
53
|
+
full: false
|
|
54
|
+
});
|
|
55
|
+
return { content: [{ type: "text", text: result }] };
|
|
56
|
+
} catch (error) {
|
|
57
|
+
return {
|
|
58
|
+
content: [{ type: "text", text: `Erro ao executar map: ${error instanceof Error ? error.message : String(error)}` }],
|
|
59
|
+
isError: true
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
);
|
|
64
|
+
server2.registerTool(
|
|
65
|
+
"aitool_dead_code",
|
|
66
|
+
{
|
|
67
|
+
title: "Dead Code Detector",
|
|
68
|
+
description: `Detecta codigo morto: arquivos orfaos, exports nao usados, deps npm mortas.
|
|
69
|
+
Use antes de refatoracoes ou periodicamente para limpeza.
|
|
70
|
+
|
|
71
|
+
Parametros:
|
|
72
|
+
- format: text (legivel) ou json (estruturado)
|
|
73
|
+
- cwd: Diretorio do projeto a analisar`,
|
|
74
|
+
inputSchema: {
|
|
75
|
+
format: z.enum(["text", "json"]).default("text").describe("Formato de saida: text (legivel) ou json (estruturado)"),
|
|
76
|
+
cwd: z.string().optional().describe("Diretorio do projeto a analisar")
|
|
77
|
+
},
|
|
78
|
+
annotations: {
|
|
79
|
+
title: "Dead Code Detector",
|
|
80
|
+
readOnlyHint: true,
|
|
81
|
+
destructiveHint: false,
|
|
82
|
+
idempotentHint: true,
|
|
83
|
+
openWorldHint: false
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
async (params) => {
|
|
87
|
+
try {
|
|
88
|
+
const result = await dead({
|
|
89
|
+
format: params.format,
|
|
90
|
+
cwd: params.cwd
|
|
91
|
+
});
|
|
92
|
+
return { content: [{ type: "text", text: result }] };
|
|
93
|
+
} catch (error) {
|
|
94
|
+
return {
|
|
95
|
+
content: [{ type: "text", text: `Erro ao executar dead: ${error instanceof Error ? error.message : String(error)}` }],
|
|
96
|
+
isError: true
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
);
|
|
101
|
+
server2.registerTool(
|
|
102
|
+
"aitool_impact_analysis",
|
|
103
|
+
{
|
|
104
|
+
title: "Impact Analysis",
|
|
105
|
+
description: `Analisa impacto de modificar um arquivo: upstream (quem importa), downstream (o que importa), riscos.
|
|
106
|
+
Use ANTES de editar arquivos para planejar mudancas seguras.
|
|
107
|
+
|
|
108
|
+
Parametros:
|
|
109
|
+
- target: Arquivo a analisar (caminho completo, parcial ou nome)
|
|
110
|
+
- format: text (legivel) ou json (estruturado)
|
|
111
|
+
- cwd: Diretorio do projeto a analisar`,
|
|
112
|
+
inputSchema: {
|
|
113
|
+
target: z.string().min(1).describe("Arquivo a analisar: caminho completo, parcial ou nome do arquivo"),
|
|
114
|
+
format: z.enum(["text", "json"]).default("text").describe("Formato de saida: text (legivel) ou json (estruturado)"),
|
|
115
|
+
cwd: z.string().optional().describe("Diretorio do projeto a analisar")
|
|
116
|
+
},
|
|
117
|
+
annotations: {
|
|
118
|
+
title: "Impact Analysis",
|
|
119
|
+
readOnlyHint: true,
|
|
120
|
+
destructiveHint: false,
|
|
121
|
+
idempotentHint: true,
|
|
122
|
+
openWorldHint: false
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
async (params) => {
|
|
126
|
+
try {
|
|
127
|
+
const result = await impact(params.target, {
|
|
128
|
+
format: params.format,
|
|
129
|
+
cwd: params.cwd
|
|
130
|
+
});
|
|
131
|
+
return { content: [{ type: "text", text: result }] };
|
|
132
|
+
} catch (error) {
|
|
133
|
+
return {
|
|
134
|
+
content: [{ type: "text", text: `Erro ao executar impact: ${error instanceof Error ? error.message : String(error)}` }],
|
|
135
|
+
isError: true
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
);
|
|
140
|
+
server2.registerTool(
|
|
141
|
+
"aitool_suggest_reads",
|
|
142
|
+
{
|
|
143
|
+
title: "Suggest Files to Read",
|
|
144
|
+
description: `Sugere arquivos para ler ANTES de modificar um arquivo.
|
|
145
|
+
Prioriza: tipos usados, dependencias diretas, upstream, testes.
|
|
146
|
+
|
|
147
|
+
Parametros:
|
|
148
|
+
- target: Arquivo que sera modificado (caminho completo, parcial ou nome)
|
|
149
|
+
- limit: Numero maximo de sugestoes (default: 10, max: 50)`,
|
|
150
|
+
inputSchema: {
|
|
151
|
+
target: z.string().min(1).describe("Arquivo que sera modificado: caminho completo, parcial ou nome"),
|
|
152
|
+
limit: z.number().int().min(1).max(50).default(10).describe("Numero maximo de sugestoes (default: 10, max: 50)"),
|
|
153
|
+
cwd: z.string().optional().describe("Diretorio do projeto a analisar")
|
|
154
|
+
},
|
|
155
|
+
annotations: {
|
|
156
|
+
title: "Suggest Files to Read",
|
|
157
|
+
readOnlyHint: true,
|
|
158
|
+
destructiveHint: false,
|
|
159
|
+
idempotentHint: true,
|
|
160
|
+
openWorldHint: false
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
async (params) => {
|
|
164
|
+
try {
|
|
165
|
+
const result = await suggest(params.target, {
|
|
166
|
+
limit: params.limit,
|
|
167
|
+
cwd: params.cwd,
|
|
168
|
+
format: "text"
|
|
169
|
+
});
|
|
170
|
+
return { content: [{ type: "text", text: result }] };
|
|
171
|
+
} catch (error) {
|
|
172
|
+
return {
|
|
173
|
+
content: [{ type: "text", text: `Erro ao executar suggest: ${error instanceof Error ? error.message : String(error)}` }],
|
|
174
|
+
isError: true
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
);
|
|
179
|
+
server2.registerTool(
|
|
180
|
+
"aitool_file_context",
|
|
181
|
+
{
|
|
182
|
+
title: "Extract File Context",
|
|
183
|
+
description: `Extrai assinaturas de funcoes e tipos de um arquivo (sem implementacao).
|
|
184
|
+
Use para entender a API publica antes de usar ou modificar.
|
|
185
|
+
|
|
186
|
+
Parametros:
|
|
187
|
+
- target: Arquivo para extrair contexto (caminho completo, parcial ou nome)
|
|
188
|
+
- cwd: Diretorio do projeto a analisar`,
|
|
189
|
+
inputSchema: {
|
|
190
|
+
target: z.string().min(1).describe("Arquivo para extrair contexto: caminho completo, parcial ou nome"),
|
|
191
|
+
cwd: z.string().optional().describe("Diretorio do projeto a analisar")
|
|
192
|
+
},
|
|
193
|
+
annotations: {
|
|
194
|
+
title: "Extract File Context",
|
|
195
|
+
readOnlyHint: true,
|
|
196
|
+
destructiveHint: false,
|
|
197
|
+
idempotentHint: true,
|
|
198
|
+
openWorldHint: false
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
async (params) => {
|
|
202
|
+
try {
|
|
203
|
+
const result = await context(params.target, {
|
|
204
|
+
cwd: params.cwd,
|
|
205
|
+
format: "text"
|
|
206
|
+
});
|
|
207
|
+
return { content: [{ type: "text", text: result }] };
|
|
208
|
+
} catch (error) {
|
|
209
|
+
return {
|
|
210
|
+
content: [{ type: "text", text: `Erro ao executar context: ${error instanceof Error ? error.message : String(error)}` }],
|
|
211
|
+
isError: true
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
);
|
|
216
|
+
server2.registerTool(
|
|
217
|
+
"aitool_list_areas",
|
|
218
|
+
{
|
|
219
|
+
title: "List Project Areas",
|
|
220
|
+
description: `Lista areas/dominios funcionais do projeto (auth, pets, stripe...).
|
|
221
|
+
Diferente de categorias (hook, component). Use area_detail para ver arquivos.
|
|
222
|
+
|
|
223
|
+
Parametros:
|
|
224
|
+
- format: text (legivel) ou json (estruturado)
|
|
225
|
+
- cwd: Diretorio do projeto a analisar`,
|
|
226
|
+
inputSchema: {
|
|
227
|
+
format: z.enum(["text", "json"]).default("text").describe("Formato de saida: text (legivel) ou json (estruturado)"),
|
|
228
|
+
cwd: z.string().optional().describe("Diretorio do projeto a analisar")
|
|
229
|
+
},
|
|
230
|
+
annotations: {
|
|
231
|
+
title: "List Project Areas",
|
|
232
|
+
readOnlyHint: true,
|
|
233
|
+
destructiveHint: false,
|
|
234
|
+
idempotentHint: true,
|
|
235
|
+
openWorldHint: false
|
|
236
|
+
}
|
|
237
|
+
},
|
|
238
|
+
async (params) => {
|
|
239
|
+
try {
|
|
240
|
+
const result = await areas({
|
|
241
|
+
format: params.format,
|
|
242
|
+
cwd: params.cwd
|
|
243
|
+
});
|
|
244
|
+
return { content: [{ type: "text", text: result }] };
|
|
245
|
+
} catch (error) {
|
|
246
|
+
return {
|
|
247
|
+
content: [{ type: "text", text: `Erro ao executar areas: ${error instanceof Error ? error.message : String(error)}` }],
|
|
248
|
+
isError: true
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
);
|
|
253
|
+
server2.registerTool(
|
|
254
|
+
"aitool_area_detail",
|
|
255
|
+
{
|
|
256
|
+
title: "Area Detail",
|
|
257
|
+
description: `Mostra arquivos de uma area especifica, agrupados por categoria.
|
|
258
|
+
Use ID (ex: auth) ou Name (ex: Autentica\xE7\xE3o) para identificar a area.
|
|
259
|
+
|
|
260
|
+
Parametros:
|
|
261
|
+
- target: Nome da area (ex: auth, dashboard, billing)
|
|
262
|
+
- type: Filtrar por categoria (page, component, hook, service, etc)
|
|
263
|
+
- full: Mostrar todos os arquivos (default: resumido)
|
|
264
|
+
- cwd: Diretorio do projeto a analisar`,
|
|
265
|
+
inputSchema: {
|
|
266
|
+
target: z.string().min(1).describe("Nome da area: auth, dashboard, billing, etc"),
|
|
267
|
+
type: z.enum(["page", "layout", "route", "component", "hook", "service", "store", "util", "type", "config", "test", "other"]).optional().describe("Filtrar por categoria especifica"),
|
|
268
|
+
full: z.boolean().default(false).describe("Mostrar todos os arquivos (default: resumido)"),
|
|
269
|
+
cwd: z.string().optional().describe("Diretorio do projeto a analisar")
|
|
270
|
+
},
|
|
271
|
+
annotations: {
|
|
272
|
+
title: "Area Detail",
|
|
273
|
+
readOnlyHint: true,
|
|
274
|
+
destructiveHint: false,
|
|
275
|
+
idempotentHint: true,
|
|
276
|
+
openWorldHint: false
|
|
277
|
+
}
|
|
278
|
+
},
|
|
279
|
+
async (params) => {
|
|
280
|
+
try {
|
|
281
|
+
const result = await area(params.target, {
|
|
282
|
+
type: params.type,
|
|
283
|
+
full: params.full,
|
|
284
|
+
cwd: params.cwd,
|
|
285
|
+
format: "text"
|
|
286
|
+
});
|
|
287
|
+
return { content: [{ type: "text", text: result }] };
|
|
288
|
+
} catch (error) {
|
|
289
|
+
return {
|
|
290
|
+
content: [{ type: "text", text: `Erro ao executar area: ${error instanceof Error ? error.message : String(error)}` }],
|
|
291
|
+
isError: true
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
);
|
|
296
|
+
server2.registerTool(
|
|
297
|
+
"aitool_areas_init",
|
|
298
|
+
{
|
|
299
|
+
title: "Initialize Areas Config",
|
|
300
|
+
description: `Gera .analyze/areas.config.json para customizar deteccao de areas.
|
|
301
|
+
Use quando houver arquivos sem area ou precisar ajustar deteccao.
|
|
302
|
+
|
|
303
|
+
Parametros:
|
|
304
|
+
- force: Sobrescrever config existente
|
|
305
|
+
- cwd: Diretorio do projeto`,
|
|
306
|
+
inputSchema: {
|
|
307
|
+
force: z.boolean().default(false).describe("Sobrescrever config existente"),
|
|
308
|
+
cwd: z.string().optional().describe("Diretorio do projeto")
|
|
309
|
+
},
|
|
310
|
+
annotations: {
|
|
311
|
+
title: "Initialize Areas Config",
|
|
312
|
+
readOnlyHint: false,
|
|
313
|
+
destructiveHint: false,
|
|
314
|
+
idempotentHint: false,
|
|
315
|
+
openWorldHint: false
|
|
316
|
+
}
|
|
317
|
+
},
|
|
318
|
+
async (params) => {
|
|
319
|
+
try {
|
|
320
|
+
const result = await areasInit({
|
|
321
|
+
force: params.force,
|
|
322
|
+
cwd: params.cwd
|
|
323
|
+
});
|
|
324
|
+
return { content: [{ type: "text", text: result }] };
|
|
325
|
+
} catch (error) {
|
|
326
|
+
return {
|
|
327
|
+
content: [{ type: "text", text: `Erro ao executar areas init: ${error instanceof Error ? error.message : String(error)}` }],
|
|
328
|
+
isError: true
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
);
|
|
333
|
+
server2.registerTool(
|
|
334
|
+
"aitool_find",
|
|
335
|
+
{
|
|
336
|
+
title: "Find Symbol",
|
|
337
|
+
description: `Busca simbolos no codigo: funcoes, tipos, componentes, hooks, constantes.
|
|
338
|
+
Retorna definicao + referencias/usos. Diferente de grep, entende o AST do TypeScript.
|
|
339
|
+
|
|
340
|
+
Parametros:
|
|
341
|
+
- query: Termo a buscar (ex: useAuth, User, login)
|
|
342
|
+
- type: Filtrar por tipo (function, type, const, component, hook, trigger, all)
|
|
343
|
+
- area: Buscar apenas em uma area especifica (ex: auth, dashboard)
|
|
344
|
+
- def: Mostrar apenas definicoes (onde e declarado)
|
|
345
|
+
- refs: Mostrar apenas referencias/usos`,
|
|
346
|
+
inputSchema: {
|
|
347
|
+
query: z.string().min(1).describe("Termo a buscar (nome de funcao, tipo, componente, etc)"),
|
|
348
|
+
type: z.enum(["function", "type", "const", "component", "hook", "trigger", "all"]).default("all").describe("Filtrar por tipo de simbolo (use trigger para Cloud Functions)"),
|
|
349
|
+
area: z.string().optional().describe("Filtrar busca por area especifica (ex: auth, dashboard)"),
|
|
350
|
+
def: z.boolean().default(false).describe("Mostrar apenas definicoes (onde e declarado)"),
|
|
351
|
+
refs: z.boolean().default(false).describe("Mostrar apenas referencias (onde e usado)"),
|
|
352
|
+
cwd: z.string().optional().describe("Diretorio do projeto a analisar")
|
|
353
|
+
},
|
|
354
|
+
annotations: {
|
|
355
|
+
title: "Find Symbol",
|
|
356
|
+
readOnlyHint: true,
|
|
357
|
+
destructiveHint: false,
|
|
358
|
+
idempotentHint: true,
|
|
359
|
+
openWorldHint: false
|
|
360
|
+
}
|
|
361
|
+
},
|
|
362
|
+
async (params) => {
|
|
363
|
+
try {
|
|
364
|
+
const result = await find(params.query, {
|
|
365
|
+
type: params.type,
|
|
366
|
+
area: params.area,
|
|
367
|
+
def: params.def,
|
|
368
|
+
refs: params.refs,
|
|
369
|
+
cwd: params.cwd,
|
|
370
|
+
format: "text"
|
|
371
|
+
});
|
|
372
|
+
return { content: [{ type: "text", text: result }] };
|
|
373
|
+
} catch (error) {
|
|
374
|
+
return {
|
|
375
|
+
content: [{ type: "text", text: `Erro ao executar find: ${error instanceof Error ? error.message : String(error)}` }],
|
|
376
|
+
isError: true
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
);
|
|
381
|
+
server2.registerTool(
|
|
382
|
+
"aitool_area_context",
|
|
383
|
+
{
|
|
384
|
+
title: "Area Context",
|
|
385
|
+
description: `Contexto consolidado de toda uma area: tipos, hooks, funcoes, componentes, services, stores.
|
|
386
|
+
Uma chamada = entender toda a feature. Muito mais eficiente que chamar context em cada arquivo.
|
|
387
|
+
|
|
388
|
+
Parametros:
|
|
389
|
+
- area: Nome da area (ex: auth, dashboard, payments)
|
|
390
|
+
- cwd: Diretorio do projeto a analisar`,
|
|
391
|
+
inputSchema: {
|
|
392
|
+
area: z.string().min(1).describe("Nome da area: auth, dashboard, payments, etc"),
|
|
393
|
+
cwd: z.string().optional().describe("Diretorio do projeto a analisar")
|
|
394
|
+
},
|
|
395
|
+
annotations: {
|
|
396
|
+
title: "Area Context",
|
|
397
|
+
readOnlyHint: true,
|
|
398
|
+
destructiveHint: false,
|
|
399
|
+
idempotentHint: true,
|
|
400
|
+
openWorldHint: false
|
|
401
|
+
}
|
|
402
|
+
},
|
|
403
|
+
async (params) => {
|
|
404
|
+
try {
|
|
405
|
+
const result = await areaContext(params.area, {
|
|
406
|
+
cwd: params.cwd,
|
|
407
|
+
format: "text"
|
|
408
|
+
});
|
|
409
|
+
return { content: [{ type: "text", text: result }] };
|
|
410
|
+
} catch (error) {
|
|
411
|
+
return {
|
|
412
|
+
content: [{ type: "text", text: `Erro ao executar area context: ${error instanceof Error ? error.message : String(error)}` }],
|
|
413
|
+
isError: true
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
);
|
|
418
|
+
server2.registerTool(
|
|
419
|
+
"aitool_list_functions",
|
|
420
|
+
{
|
|
421
|
+
title: "List Cloud Functions",
|
|
422
|
+
description: `Lista todas as Cloud Functions Firebase do projeto.
|
|
423
|
+
Agrupa por tipo de trigger (onCall, onDocumentCreated, onSchedule, etc).
|
|
424
|
+
Use para entender a arquitetura serverless antes de modificar triggers.
|
|
425
|
+
|
|
426
|
+
Parametros:
|
|
427
|
+
- trigger: Filtrar por tipo de trigger (ex: onCall, onDocumentCreated, onSchedule)
|
|
428
|
+
- format: text (legivel) ou json (estruturado)`,
|
|
429
|
+
inputSchema: {
|
|
430
|
+
trigger: z.string().optional().describe("Filtrar por tipo de trigger (ex: onCall, onDocumentCreated, onSchedule)"),
|
|
431
|
+
format: z.enum(["text", "json"]).default("text").describe("Formato de saida: text (legivel) ou json (estruturado)"),
|
|
432
|
+
cwd: z.string().optional().describe("Diretorio do projeto a analisar")
|
|
433
|
+
},
|
|
434
|
+
annotations: {
|
|
435
|
+
title: "List Cloud Functions",
|
|
436
|
+
readOnlyHint: true,
|
|
437
|
+
destructiveHint: false,
|
|
438
|
+
idempotentHint: true,
|
|
439
|
+
openWorldHint: false
|
|
440
|
+
}
|
|
441
|
+
},
|
|
442
|
+
async (params) => {
|
|
443
|
+
try {
|
|
444
|
+
const result = await functions({
|
|
445
|
+
format: params.format,
|
|
446
|
+
trigger: params.trigger,
|
|
447
|
+
cwd: params.cwd
|
|
448
|
+
});
|
|
449
|
+
return { content: [{ type: "text", text: result }] };
|
|
450
|
+
} catch (error) {
|
|
451
|
+
return {
|
|
452
|
+
content: [{ type: "text", text: `Erro ao executar functions: ${error instanceof Error ? error.message : String(error)}` }],
|
|
453
|
+
isError: true
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
);
|
|
458
|
+
server2.registerTool(
|
|
459
|
+
"aitool_describe",
|
|
460
|
+
{
|
|
461
|
+
title: "Search by Description",
|
|
462
|
+
description: `Busca \xE1reas por descri\xE7\xE3o em linguagem natural.
|
|
463
|
+
Ex: "Onde implementou login?" \u2192 encontra \xE1rea de autentica\xE7\xE3o.
|
|
464
|
+
|
|
465
|
+
Parametros:
|
|
466
|
+
- query: Descri\xE7\xE3o ou keyword
|
|
467
|
+
- cwd: Diretorio do projeto`,
|
|
468
|
+
inputSchema: {
|
|
469
|
+
query: z.string().min(1).describe("Descri\xE7\xE3o ou keyword para buscar \xE1reas"),
|
|
470
|
+
format: z.enum(["text", "json"]).default("text").describe("Formato de saida: text (legivel) ou json (estruturado)"),
|
|
471
|
+
cwd: z.string().optional().describe("Diretorio do projeto a analisar")
|
|
472
|
+
},
|
|
473
|
+
annotations: {
|
|
474
|
+
title: "Search by Description",
|
|
475
|
+
readOnlyHint: true,
|
|
476
|
+
destructiveHint: false,
|
|
477
|
+
idempotentHint: true,
|
|
478
|
+
openWorldHint: false
|
|
479
|
+
}
|
|
480
|
+
},
|
|
481
|
+
async (params) => {
|
|
482
|
+
try {
|
|
483
|
+
const result = await describe(params.query, {
|
|
484
|
+
format: params.format,
|
|
485
|
+
cwd: params.cwd
|
|
486
|
+
});
|
|
487
|
+
return { content: [{ type: "text", text: result }] };
|
|
488
|
+
} catch (error) {
|
|
489
|
+
return {
|
|
490
|
+
content: [{ type: "text", text: `Erro ao executar describe: ${error instanceof Error ? error.message : String(error)}` }],
|
|
491
|
+
isError: true
|
|
492
|
+
};
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
);
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// src/mcp/server.ts
|
|
499
|
+
var server = new McpServer({
|
|
500
|
+
name: "ai-tool-mcp-server",
|
|
501
|
+
version: VERSION
|
|
502
|
+
});
|
|
503
|
+
registerAllTools(server);
|
|
504
|
+
async function startMcpServer() {
|
|
505
|
+
const transport = new StdioServerTransport();
|
|
506
|
+
await server.connect(transport);
|
|
507
|
+
console.error(`[ai-tool] MCP server v${VERSION} running via stdio`);
|
|
508
|
+
}
|
|
509
|
+
export {
|
|
510
|
+
startMcpServer
|
|
511
|
+
};
|