@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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@justmpm/ai-tool",
3
- "version": "0.8.2",
4
- "description": "Ferramenta de análise de dependências e impacto para projetos TypeScript/JavaScript. Usa Skott + Knip internamente.",
3
+ "version": "0.9.1",
4
+ "description": "Ferramenta de análise de dependências e impacto para projetos TypeScript/JavaScript. Usa Skott + Knip internamente. Inclui busca por descrição, integração Git e testes inteligentes.",
5
5
  "keywords": [
6
6
  "dependency-analysis",
7
7
  "impact-analysis",
@@ -39,7 +39,7 @@
39
39
  "build": "tsup src/index.ts src/cli.ts --format esm --dts --clean",
40
40
  "dev": "tsup src/index.ts src/cli.ts --format esm --dts --watch",
41
41
  "prepublishOnly": "npm run build",
42
- "test": "node --test",
42
+ "test": "tsx --test",
43
43
  "typecheck": "tsc --noEmit"
44
44
  },
45
45
  "dependencies": {
@@ -52,6 +52,7 @@
52
52
  },
53
53
  "devDependencies": {
54
54
  "@types/node": "^22.15.21",
55
+ "tsx": "^4.19.0",
55
56
  "tsup": "^8.5.0",
56
57
  "typescript": "^5.8.3"
57
58
  },
@@ -1,537 +0,0 @@
1
- import {
2
- VERSION,
3
- area,
4
- areaContext,
5
- areas,
6
- areasInit,
7
- context,
8
- dead,
9
- find,
10
- functions,
11
- impact,
12
- map,
13
- suggest
14
- } from "./chunk-OMEBMR2V.js";
15
-
16
- // src/mcp/server.ts
17
- import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
18
- import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
19
- import { z } from "zod";
20
- var server = new McpServer({
21
- name: "ai-tool-mcp-server",
22
- version: VERSION
23
- });
24
- server.registerTool(
25
- "aitool_project_map",
26
- {
27
- title: "Project Map",
28
- description: `Mapeia projeto e retorna resumo: contagens por categoria, areas detectadas, alertas.
29
- Use no inicio da sessao. Para detalhes: area_detail, file_context, suggest_reads.
30
-
31
- Parametros:
32
- - format: text (legivel) ou json (estruturado)
33
- - cwd: Diretorio do projeto a analisar`,
34
- inputSchema: {
35
- format: z.enum(["text", "json"]).default("text").describe("Formato de saida: text (legivel) ou json (estruturado)"),
36
- cwd: z.string().optional().describe("Diretorio do projeto a analisar")
37
- },
38
- annotations: {
39
- title: "Project Map",
40
- readOnlyHint: true,
41
- destructiveHint: false,
42
- idempotentHint: true,
43
- openWorldHint: false
44
- }
45
- },
46
- async (params) => {
47
- try {
48
- const result = await map({
49
- format: params.format,
50
- cwd: params.cwd,
51
- full: false
52
- });
53
- return { content: [{ type: "text", text: result }] };
54
- } catch (error) {
55
- return {
56
- content: [
57
- {
58
- type: "text",
59
- text: `Erro ao executar map: ${error instanceof Error ? error.message : String(error)}`
60
- }
61
- ],
62
- isError: true
63
- };
64
- }
65
- }
66
- );
67
- server.registerTool(
68
- "aitool_dead_code",
69
- {
70
- title: "Dead Code Detector",
71
- description: `Detecta codigo morto: arquivos orfaos, exports nao usados, deps npm mortas.
72
- Use antes de refatoracoes ou periodicamente para limpeza.
73
-
74
- Parametros:
75
- - format: text (legivel) ou json (estruturado)
76
- - cwd: Diretorio do projeto a analisar`,
77
- inputSchema: {
78
- format: z.enum(["text", "json"]).default("text").describe("Formato de saida: text (legivel) ou json (estruturado)"),
79
- cwd: z.string().optional().describe("Diretorio do projeto a analisar")
80
- },
81
- annotations: {
82
- title: "Dead Code Detector",
83
- readOnlyHint: true,
84
- destructiveHint: false,
85
- idempotentHint: true,
86
- openWorldHint: false
87
- }
88
- },
89
- async (params) => {
90
- try {
91
- const result = await dead({
92
- format: params.format,
93
- cwd: params.cwd
94
- });
95
- return { content: [{ type: "text", text: result }] };
96
- } catch (error) {
97
- return {
98
- content: [
99
- {
100
- type: "text",
101
- text: `Erro ao executar dead: ${error instanceof Error ? error.message : String(error)}`
102
- }
103
- ],
104
- isError: true
105
- };
106
- }
107
- }
108
- );
109
- server.registerTool(
110
- "aitool_impact_analysis",
111
- {
112
- title: "Impact Analysis",
113
- description: `Analisa impacto de modificar um arquivo: upstream (quem importa), downstream (o que importa), riscos.
114
- Use ANTES de editar arquivos para planejar mudancas seguras.
115
-
116
- Parametros:
117
- - target: Arquivo a analisar (caminho completo, parcial ou nome)
118
- - format: text (legivel) ou json (estruturado)
119
- - cwd: Diretorio do projeto a analisar`,
120
- inputSchema: {
121
- target: z.string().min(1).describe(
122
- "Arquivo a analisar: caminho completo, parcial ou nome do arquivo"
123
- ),
124
- format: z.enum(["text", "json"]).default("text").describe("Formato de saida: text (legivel) ou json (estruturado)"),
125
- cwd: z.string().optional().describe("Diretorio do projeto a analisar")
126
- },
127
- annotations: {
128
- title: "Impact Analysis",
129
- readOnlyHint: true,
130
- destructiveHint: false,
131
- idempotentHint: true,
132
- openWorldHint: false
133
- }
134
- },
135
- async (params) => {
136
- try {
137
- const result = await impact(params.target, {
138
- format: params.format,
139
- cwd: params.cwd
140
- });
141
- return { content: [{ type: "text", text: result }] };
142
- } catch (error) {
143
- return {
144
- content: [
145
- {
146
- type: "text",
147
- text: `Erro ao executar impact: ${error instanceof Error ? error.message : String(error)}`
148
- }
149
- ],
150
- isError: true
151
- };
152
- }
153
- }
154
- );
155
- server.registerTool(
156
- "aitool_suggest_reads",
157
- {
158
- title: "Suggest Files to Read",
159
- description: `Sugere arquivos para ler ANTES de modificar um arquivo.
160
- Prioriza: tipos usados, dependencias diretas, upstream, testes.
161
-
162
- Parametros:
163
- - target: Arquivo que sera modificado (caminho completo, parcial ou nome)
164
- - limit: Numero maximo de sugestoes (default: 10, max: 50)`,
165
- inputSchema: {
166
- target: z.string().min(1).describe(
167
- "Arquivo que sera modificado: caminho completo, parcial ou nome"
168
- ),
169
- limit: z.number().int().min(1).max(50).default(10).describe("Numero maximo de sugestoes (default: 10, max: 50)"),
170
- cwd: z.string().optional().describe("Diretorio do projeto a analisar")
171
- },
172
- annotations: {
173
- title: "Suggest Files to Read",
174
- readOnlyHint: true,
175
- destructiveHint: false,
176
- idempotentHint: true,
177
- openWorldHint: false
178
- }
179
- },
180
- async (params) => {
181
- try {
182
- const result = await suggest(params.target, {
183
- limit: params.limit,
184
- cwd: params.cwd,
185
- format: "text"
186
- });
187
- return { content: [{ type: "text", text: result }] };
188
- } catch (error) {
189
- return {
190
- content: [
191
- {
192
- type: "text",
193
- text: `Erro ao executar suggest: ${error instanceof Error ? error.message : String(error)}`
194
- }
195
- ],
196
- isError: true
197
- };
198
- }
199
- }
200
- );
201
- server.registerTool(
202
- "aitool_file_context",
203
- {
204
- title: "Extract File Context",
205
- description: `Extrai assinaturas de funcoes e tipos de um arquivo (sem implementacao).
206
- Use para entender a API publica antes de usar ou modificar.
207
-
208
- Parametros:
209
- - target: Arquivo para extrair contexto (caminho completo, parcial ou nome)
210
- - cwd: Diretorio do projeto a analisar`,
211
- inputSchema: {
212
- target: z.string().min(1).describe(
213
- "Arquivo para extrair contexto: caminho completo, parcial ou nome"
214
- ),
215
- cwd: z.string().optional().describe("Diretorio do projeto a analisar")
216
- },
217
- annotations: {
218
- title: "Extract File Context",
219
- readOnlyHint: true,
220
- destructiveHint: false,
221
- idempotentHint: true,
222
- openWorldHint: false
223
- }
224
- },
225
- async (params) => {
226
- try {
227
- const result = await context(params.target, {
228
- cwd: params.cwd,
229
- format: "text"
230
- });
231
- return { content: [{ type: "text", text: result }] };
232
- } catch (error) {
233
- return {
234
- content: [
235
- {
236
- type: "text",
237
- text: `Erro ao executar context: ${error instanceof Error ? error.message : String(error)}`
238
- }
239
- ],
240
- isError: true
241
- };
242
- }
243
- }
244
- );
245
- server.registerTool(
246
- "aitool_list_areas",
247
- {
248
- title: "List Project Areas",
249
- description: `Lista areas/dominios funcionais do projeto (auth, pets, stripe...).
250
- Diferente de categorias (hook, component). Use area_detail para ver arquivos.
251
-
252
- Parametros:
253
- - format: text (legivel) ou json (estruturado)
254
- - cwd: Diretorio do projeto a analisar`,
255
- inputSchema: {
256
- format: z.enum(["text", "json"]).default("text").describe("Formato de saida: text (legivel) ou json (estruturado)"),
257
- cwd: z.string().optional().describe("Diretorio do projeto a analisar")
258
- },
259
- annotations: {
260
- title: "List Project Areas",
261
- readOnlyHint: true,
262
- destructiveHint: false,
263
- idempotentHint: true,
264
- openWorldHint: false
265
- }
266
- },
267
- async (params) => {
268
- try {
269
- const result = await areas({
270
- format: params.format,
271
- cwd: params.cwd
272
- });
273
- return { content: [{ type: "text", text: result }] };
274
- } catch (error) {
275
- return {
276
- content: [
277
- {
278
- type: "text",
279
- text: `Erro ao executar areas: ${error instanceof Error ? error.message : String(error)}`
280
- }
281
- ],
282
- isError: true
283
- };
284
- }
285
- }
286
- );
287
- server.registerTool(
288
- "aitool_area_detail",
289
- {
290
- title: "Area Detail",
291
- description: `Mostra arquivos de uma area especifica, agrupados por categoria.
292
- Use ID (ex: auth) ou Name (ex: Autentica\xE7\xE3o) para identificar a area.
293
-
294
- Parametros:
295
- - target: Nome da area (ex: auth, dashboard, billing)
296
- - type: Filtrar por categoria (page, component, hook, service, etc)
297
- - full: Mostrar todos os arquivos (default: resumido)
298
- - cwd: Diretorio do projeto a analisar`,
299
- inputSchema: {
300
- target: z.string().min(1).describe("Nome da area: auth, dashboard, billing, etc"),
301
- type: z.enum([
302
- "page",
303
- "layout",
304
- "route",
305
- "component",
306
- "hook",
307
- "service",
308
- "store",
309
- "util",
310
- "type",
311
- "config",
312
- "test",
313
- "other"
314
- ]).optional().describe("Filtrar por categoria especifica"),
315
- full: z.boolean().default(false).describe("Mostrar todos os arquivos (default: resumido)"),
316
- cwd: z.string().optional().describe("Diretorio do projeto a analisar")
317
- },
318
- annotations: {
319
- title: "Area Detail",
320
- readOnlyHint: true,
321
- destructiveHint: false,
322
- idempotentHint: true,
323
- openWorldHint: false
324
- }
325
- },
326
- async (params) => {
327
- try {
328
- const result = await area(params.target, {
329
- type: params.type,
330
- full: params.full,
331
- cwd: params.cwd,
332
- format: "text"
333
- });
334
- return { content: [{ type: "text", text: result }] };
335
- } catch (error) {
336
- return {
337
- content: [
338
- {
339
- type: "text",
340
- text: `Erro ao executar area: ${error instanceof Error ? error.message : String(error)}`
341
- }
342
- ],
343
- isError: true
344
- };
345
- }
346
- }
347
- );
348
- server.registerTool(
349
- "aitool_areas_init",
350
- {
351
- title: "Initialize Areas Config",
352
- description: `Gera .analyze/areas.config.json para customizar deteccao de areas.
353
- Use quando houver arquivos sem area ou precisar ajustar deteccao.
354
-
355
- Parametros:
356
- - force: Sobrescrever config existente
357
- - cwd: Diretorio do projeto`,
358
- inputSchema: {
359
- force: z.boolean().default(false).describe("Sobrescrever config existente"),
360
- cwd: z.string().optional().describe("Diretorio do projeto")
361
- },
362
- annotations: {
363
- title: "Initialize Areas Config",
364
- readOnlyHint: false,
365
- destructiveHint: false,
366
- idempotentHint: false,
367
- openWorldHint: false
368
- }
369
- },
370
- async (params) => {
371
- try {
372
- const result = await areasInit({
373
- force: params.force,
374
- cwd: params.cwd
375
- });
376
- return { content: [{ type: "text", text: result }] };
377
- } catch (error) {
378
- return {
379
- content: [
380
- {
381
- type: "text",
382
- text: `Erro ao executar areas init: ${error instanceof Error ? error.message : String(error)}`
383
- }
384
- ],
385
- isError: true
386
- };
387
- }
388
- }
389
- );
390
- server.registerTool(
391
- "aitool_find",
392
- {
393
- title: "Find Symbol",
394
- description: `Busca simbolos no codigo: funcoes, tipos, componentes, hooks, constantes.
395
- Retorna definicao + referencias/usos. Diferente de grep, entende o AST do TypeScript.
396
-
397
- Parametros:
398
- - query: Termo a buscar (ex: useAuth, User, login)
399
- - type: Filtrar por tipo (function, type, const, component, hook, trigger, all)
400
- - area: Buscar apenas em uma area especifica (ex: auth, dashboard)
401
- - def: Mostrar apenas definicoes (onde e declarado)
402
- - refs: Mostrar apenas referencias/usos`,
403
- inputSchema: {
404
- query: z.string().min(1).describe("Termo a buscar (nome de funcao, tipo, componente, etc)"),
405
- type: z.enum(["function", "type", "const", "component", "hook", "trigger", "all"]).default("all").describe("Filtrar por tipo de simbolo (use trigger para Cloud Functions)"),
406
- area: z.string().optional().describe("Filtrar busca por area especifica (ex: auth, dashboard)"),
407
- def: z.boolean().default(false).describe("Mostrar apenas definicoes (onde e declarado)"),
408
- refs: z.boolean().default(false).describe("Mostrar apenas referencias (onde e usado)"),
409
- cwd: z.string().optional().describe("Diretorio do projeto a analisar")
410
- },
411
- annotations: {
412
- title: "Find Symbol",
413
- readOnlyHint: true,
414
- destructiveHint: false,
415
- idempotentHint: true,
416
- openWorldHint: false
417
- }
418
- },
419
- async (params) => {
420
- try {
421
- const result = await find(params.query, {
422
- type: params.type,
423
- area: params.area,
424
- def: params.def,
425
- refs: params.refs,
426
- cwd: params.cwd,
427
- format: "text"
428
- });
429
- return { content: [{ type: "text", text: result }] };
430
- } catch (error) {
431
- return {
432
- content: [
433
- {
434
- type: "text",
435
- text: `Erro ao executar find: ${error instanceof Error ? error.message : String(error)}`
436
- }
437
- ],
438
- isError: true
439
- };
440
- }
441
- }
442
- );
443
- server.registerTool(
444
- "aitool_area_context",
445
- {
446
- title: "Area Context",
447
- description: `Contexto consolidado de toda uma area: tipos, hooks, funcoes, componentes, services, stores.
448
- Uma chamada = entender toda a feature. Muito mais eficiente que chamar context em cada arquivo.
449
-
450
- Parametros:
451
- - area: Nome da area (ex: auth, dashboard, payments)
452
- - cwd: Diretorio do projeto a analisar`,
453
- inputSchema: {
454
- area: z.string().min(1).describe("Nome da area: auth, dashboard, payments, etc"),
455
- cwd: z.string().optional().describe("Diretorio do projeto a analisar")
456
- },
457
- annotations: {
458
- title: "Area Context",
459
- readOnlyHint: true,
460
- destructiveHint: false,
461
- idempotentHint: true,
462
- openWorldHint: false
463
- }
464
- },
465
- async (params) => {
466
- try {
467
- const result = await areaContext(params.area, {
468
- cwd: params.cwd,
469
- format: "text"
470
- });
471
- return { content: [{ type: "text", text: result }] };
472
- } catch (error) {
473
- return {
474
- content: [
475
- {
476
- type: "text",
477
- text: `Erro ao executar area context: ${error instanceof Error ? error.message : String(error)}`
478
- }
479
- ],
480
- isError: true
481
- };
482
- }
483
- }
484
- );
485
- server.registerTool(
486
- "aitool_list_functions",
487
- {
488
- title: "List Cloud Functions",
489
- description: `Lista todas as Cloud Functions Firebase do projeto.
490
- Agrupa por tipo de trigger (onCall, onDocumentCreated, onSchedule, etc).
491
- Use para entender a arquitetura serverless antes de modificar triggers.
492
-
493
- Parametros:
494
- - trigger: Filtrar por tipo de trigger (ex: onCall, onDocumentCreated, onSchedule)
495
- - format: text (legivel) ou json (estruturado)`,
496
- inputSchema: {
497
- trigger: z.string().optional().describe("Filtrar por tipo de trigger (ex: onCall, onDocumentCreated, onSchedule)"),
498
- format: z.enum(["text", "json"]).default("text").describe("Formato de saida: text (legivel) ou json (estruturado)"),
499
- cwd: z.string().optional().describe("Diretorio do projeto a analisar")
500
- },
501
- annotations: {
502
- title: "List Cloud Functions",
503
- readOnlyHint: true,
504
- destructiveHint: false,
505
- idempotentHint: true,
506
- openWorldHint: false
507
- }
508
- },
509
- async (params) => {
510
- try {
511
- const result = await functions({
512
- format: params.format,
513
- trigger: params.trigger,
514
- cwd: params.cwd
515
- });
516
- return { content: [{ type: "text", text: result }] };
517
- } catch (error) {
518
- return {
519
- content: [
520
- {
521
- type: "text",
522
- text: `Erro ao executar functions: ${error instanceof Error ? error.message : String(error)}`
523
- }
524
- ],
525
- isError: true
526
- };
527
- }
528
- }
529
- );
530
- async function startMcpServer() {
531
- const transport = new StdioServerTransport();
532
- await server.connect(transport);
533
- console.error(`[ai-tool] MCP server v${VERSION} running via stdio`);
534
- }
535
- export {
536
- startMcpServer
537
- };