@justmpm/ai-tool 0.2.0 → 0.3.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/dist/cli.js CHANGED
@@ -1,33 +1,41 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  VERSION,
4
+ context,
4
5
  dead,
5
6
  deadFix,
6
7
  impact,
7
- map
8
- } from "./chunk-HOVHD2N4.js";
8
+ map,
9
+ suggest
10
+ } from "./chunk-4HXWM7PK.js";
9
11
 
10
12
  // src/cli.ts
11
13
  var HELP = `
12
- ai-tool v${VERSION} - An\xE1lise de depend\xEAncias e impacto
14
+ ai-tool v${VERSION} - Analise de dependencias e impacto
13
15
 
14
16
  COMANDOS:
15
17
  map Mapa completo do projeto (usa Skott)
16
- dead Detecta c\xF3digo morto (usa Knip)
17
- dead --fix Remove c\xF3digo morto automaticamente
18
- impact <arquivo> An\xE1lise de impacto antes de modificar
18
+ dead Detecta codigo morto (usa Knip)
19
+ dead --fix Remove codigo morto automaticamente
20
+ impact <arquivo> Analise de impacto antes de modificar
21
+ suggest <arquivo> Sugere arquivos para ler antes de modificar
22
+ context <arquivo> Extrai assinaturas de um arquivo (funcoes, tipos)
19
23
 
20
- OP\xC7\xD5ES:
21
- --format=text|json Formato de sa\xEDda (default: text)
22
- --cwd=<path> Diret\xF3rio do projeto (default: cwd)
23
- --no-cache Ignora cache e for\xE7a regenera\xE7\xE3o
24
+ MODOS:
25
+ --mcp Inicia servidor MCP para integracao com Claude Desktop
26
+
27
+ OPCOES:
28
+ --format=text|json Formato de saida (default: text)
29
+ --cwd=<path> Diretorio do projeto (default: cwd)
30
+ --no-cache Ignora cache e forca regeneracao
31
+ --limit=<n> Limite de sugestoes (default: 10, apenas suggest)
24
32
  --help, -h Mostra esta ajuda
25
- --version, -v Mostra vers\xE3o
33
+ --version, -v Mostra versao
26
34
 
27
35
  CACHE:
28
- Resultados s\xE3o salvos em .analyze/ para acelerar execu\xE7\xF5es futuras.
29
- O cache \xE9 invalidado automaticamente quando arquivos mudam.
30
- Use --no-cache para for\xE7ar regenera\xE7\xE3o.
36
+ Resultados sao salvos em .analyze/ para acelerar execucoes futuras.
37
+ O cache e invalidado automaticamente quando arquivos mudam.
38
+ Use --no-cache para forcar regeneracao.
31
39
 
32
40
  EXEMPLOS:
33
41
  ai-tool map
@@ -38,10 +46,15 @@ EXEMPLOS:
38
46
  ai-tool impact Button
39
47
  ai-tool impact src/hooks/useAuth.ts
40
48
  ai-tool impact src/components/Header.tsx --format=json
49
+ ai-tool suggest Button
50
+ ai-tool suggest src/hooks/useAuth.ts --limit=5
51
+ ai-tool context Button
52
+ ai-tool context src/hooks/useAuth.ts --format=json
53
+ ai-tool --mcp
41
54
 
42
55
  SOBRE:
43
56
  Criado por Koda AI Studio (kodaai.app)
44
- Usa Skott para an\xE1lise de depend\xEAncias e Knip para dead code detection.
57
+ Usa Skott para analise de dependencias e Knip para dead code detection.
45
58
  `;
46
59
  async function main() {
47
60
  const args = process.argv.slice(2);
@@ -58,6 +71,11 @@ async function main() {
58
71
  positional.push(arg);
59
72
  }
60
73
  }
74
+ if (flags.mcp) {
75
+ const { startMcpServer } = await import("./server-YV4BWISA.js");
76
+ await startMcpServer();
77
+ return;
78
+ }
61
79
  if (flags.help || flags.h || positional.length === 0) {
62
80
  console.log(HELP);
63
81
  process.exit(0);
@@ -93,6 +111,29 @@ async function main() {
93
111
  }
94
112
  result = await impact(target, { format, cwd, cache });
95
113
  break;
114
+ case "suggest":
115
+ if (!target) {
116
+ console.error("\u274C Erro: arquivo alvo \xE9 obrigat\xF3rio para o comando suggest");
117
+ console.error(" Exemplo: ai-tool suggest src/components/Button.tsx");
118
+ console.error(" Exemplo: ai-tool suggest Button");
119
+ process.exit(1);
120
+ }
121
+ result = await suggest(target, {
122
+ format,
123
+ cwd,
124
+ cache,
125
+ limit: flags.limit ? Number(flags.limit) : void 0
126
+ });
127
+ break;
128
+ case "context":
129
+ if (!target) {
130
+ console.error("\u274C Erro: arquivo alvo \xE9 obrigat\xF3rio para o comando context");
131
+ console.error(" Exemplo: ai-tool context src/components/Button.tsx");
132
+ console.error(" Exemplo: ai-tool context Button");
133
+ process.exit(1);
134
+ }
135
+ result = await context(target, { format, cwd });
136
+ break;
96
137
  default:
97
138
  console.error(`\u274C Comando desconhecido: ${command}`);
98
139
  console.error(" Use 'ai-tool --help' para ver comandos dispon\xEDveis.");
package/dist/index.d.ts CHANGED
@@ -95,6 +95,61 @@ interface ImpactResult {
95
95
  risks: RiskInfo[];
96
96
  suggestions: string[];
97
97
  }
98
+ interface SuggestOptions extends CommandOptions {
99
+ limit?: number;
100
+ }
101
+ type SuggestionPriority = "critical" | "high" | "medium" | "low";
102
+ interface Suggestion {
103
+ path: string;
104
+ category: FileCategory;
105
+ reason: string;
106
+ priority: SuggestionPriority;
107
+ }
108
+ interface SuggestResult {
109
+ version: string;
110
+ timestamp: string;
111
+ target: string;
112
+ category: FileCategory;
113
+ suggestions: Suggestion[];
114
+ }
115
+ interface ContextOptions extends CommandOptions {
116
+ depth?: number;
117
+ }
118
+ interface ImportInfo {
119
+ source: string;
120
+ specifiers: string[];
121
+ isTypeOnly: boolean;
122
+ }
123
+ type ParamInfo = {
124
+ name: string;
125
+ type: string;
126
+ };
127
+ interface FunctionInfo {
128
+ name: string;
129
+ params: ParamInfo[];
130
+ returnType: string;
131
+ isAsync: boolean;
132
+ isExported: boolean;
133
+ isArrowFunction: boolean;
134
+ jsdoc?: string;
135
+ }
136
+ type TypeKind = "interface" | "type" | "enum";
137
+ interface TypeInfo {
138
+ name: string;
139
+ kind: TypeKind;
140
+ definition: string;
141
+ isExported: boolean;
142
+ }
143
+ interface ContextResult {
144
+ version: string;
145
+ timestamp: string;
146
+ file: string;
147
+ category: FileCategory;
148
+ imports: ImportInfo[];
149
+ exports: string[];
150
+ functions: FunctionInfo[];
151
+ types: TypeInfo[];
152
+ }
98
153
 
99
154
  /**
100
155
  * Comando MAP - Mapa do projeto usando Skott
@@ -127,6 +182,24 @@ declare function deadFix(options?: DeadOptions): Promise<string>;
127
182
  */
128
183
  declare function impact(target: string, options?: ImpactOptions): Promise<string>;
129
184
 
185
+ /**
186
+ * Comando SUGGEST - Sugere arquivos para ler antes de modificar um arquivo
187
+ */
188
+
189
+ /**
190
+ * Executa o comando SUGGEST
191
+ */
192
+ declare function suggest(target: string, options?: SuggestOptions): Promise<string>;
193
+
194
+ /**
195
+ * Comando CONTEXT - Extrai assinaturas de funcoes e tipos de um arquivo
196
+ */
197
+
198
+ /**
199
+ * Executa o comando CONTEXT
200
+ */
201
+ declare function context(target: string, options?: ContextOptions): Promise<string>;
202
+
130
203
  /**
131
204
  * Utilitários para detecção e classificação de arquivos
132
205
  */
@@ -181,6 +254,6 @@ declare function invalidateCache(cwd: string): void;
181
254
  * ```
182
255
  */
183
256
 
184
- declare const VERSION = "0.2.0";
257
+ declare const VERSION = "0.3.1";
185
258
 
186
- export { type CommandOptions, type DeadFile, type DeadOptions, type DeadResult, type FileCategory, type FileInfo, type FolderStats, type ImpactFile, type ImpactOptions, type ImpactResult, type MapOptions, type MapResult, type OutputFormat, type RiskInfo, VERSION, categoryIcons, dead, deadFix, detectCategory, getCacheDir, impact, invalidateCache, isCacheValid, isCodeFile, isEntryPoint, map };
259
+ export { type CommandOptions, type ContextOptions, type ContextResult, type DeadFile, type DeadOptions, type DeadResult, type FileCategory, type FileInfo, type FolderStats, type FunctionInfo, type ImpactFile, type ImpactOptions, type ImpactResult, type ImportInfo, type MapOptions, type MapResult, type OutputFormat, type ParamInfo, type RiskInfo, type SuggestOptions, type SuggestResult, type Suggestion, type SuggestionPriority, type TypeInfo, type TypeKind, VERSION, categoryIcons, context, dead, deadFix, detectCategory, getCacheDir, impact, invalidateCache, isCacheValid, isCodeFile, isEntryPoint, map, suggest };
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  VERSION,
3
3
  categoryIcons,
4
+ context,
4
5
  dead,
5
6
  deadFix,
6
7
  detectCategory,
@@ -10,11 +11,13 @@ import {
10
11
  isCacheValid,
11
12
  isCodeFile,
12
13
  isEntryPoint,
13
- map
14
- } from "./chunk-HOVHD2N4.js";
14
+ map,
15
+ suggest
16
+ } from "./chunk-4HXWM7PK.js";
15
17
  export {
16
18
  VERSION,
17
19
  categoryIcons,
20
+ context,
18
21
  dead,
19
22
  deadFix,
20
23
  detectCategory,
@@ -24,5 +27,6 @@ export {
24
27
  isCacheValid,
25
28
  isCodeFile,
26
29
  isEntryPoint,
27
- map
30
+ map,
31
+ suggest
28
32
  };
@@ -0,0 +1,343 @@
1
+ import {
2
+ VERSION,
3
+ context,
4
+ dead,
5
+ impact,
6
+ map,
7
+ suggest
8
+ } from "./chunk-4HXWM7PK.js";
9
+
10
+ // src/mcp/server.ts
11
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
12
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
13
+ import { z } from "zod";
14
+ var server = new McpServer({
15
+ name: "ai-tool-mcp-server",
16
+ version: VERSION
17
+ });
18
+ server.registerTool(
19
+ "aitool_project_map",
20
+ {
21
+ title: "Project Map",
22
+ description: `Gera um mapa completo do projeto com categorias de arquivos e estrutura de pastas.
23
+
24
+ FUNCIONALIDADES:
25
+ - Lista todos os arquivos TypeScript/JavaScript do projeto
26
+ - Categoriza automaticamente: page, layout, route, component, hook, service, store, util, type, config, test
27
+ - Agrupa estatisticas por pasta
28
+ - Detecta dependencias circulares
29
+
30
+ PARAMETROS:
31
+ - format: "text" (legivel) ou "json" (estruturado)
32
+ - cwd: Diretorio do projeto (default: diretorio atual)
33
+
34
+ RETORNA:
35
+ - Sumario com total de arquivos e pastas
36
+ - Distribuicao por categoria
37
+ - Lista de pastas com contagem
38
+ - Lista de arquivos com categoria
39
+ - Dependencias circulares detectadas
40
+
41
+ EXEMPLO DE USO:
42
+ Chamar para entender a estrutura de um projeto antes de modificar.`,
43
+ inputSchema: {
44
+ format: z.enum(["text", "json"]).default("text").describe("Formato de saida: text (legivel) ou json (estruturado)"),
45
+ cwd: z.string().optional().describe("Diretorio do projeto a analisar")
46
+ },
47
+ annotations: {
48
+ title: "Project Map",
49
+ readOnlyHint: true,
50
+ destructiveHint: false,
51
+ idempotentHint: true,
52
+ openWorldHint: false
53
+ }
54
+ },
55
+ async (params) => {
56
+ try {
57
+ const result = await map({
58
+ format: params.format,
59
+ cwd: params.cwd
60
+ });
61
+ return { content: [{ type: "text", text: result }] };
62
+ } catch (error) {
63
+ return {
64
+ content: [
65
+ {
66
+ type: "text",
67
+ text: `Erro ao executar map: ${error instanceof Error ? error.message : String(error)}`
68
+ }
69
+ ],
70
+ isError: true
71
+ };
72
+ }
73
+ }
74
+ );
75
+ server.registerTool(
76
+ "aitool_dead_code",
77
+ {
78
+ title: "Dead Code Detector",
79
+ description: `Detecta codigo morto no projeto usando Knip.
80
+
81
+ DETECTA:
82
+ - Arquivos orfaos (nao importados por ninguem)
83
+ - Exports nao utilizados
84
+ - Dependencias npm nao usadas
85
+
86
+ PARAMETROS:
87
+ - format: "text" (legivel) ou "json" (estruturado)
88
+ - cwd: Diretorio do projeto (default: diretorio atual)
89
+
90
+ RETORNA:
91
+ - Sumario com total de codigo morto por tipo
92
+ - Lista de arquivos orfaos com categoria
93
+ - Lista de exports nao usados (arquivo + nome)
94
+ - Lista de dependencias npm nao usadas
95
+
96
+ EXEMPLO DE USO:
97
+ Chamar periodicamente para manter o projeto limpo.
98
+ Chamar antes de refatoracoes para identificar codigo removivel.
99
+
100
+ NOTA: Requer que o projeto tenha knip configurado ou use defaults.`,
101
+ inputSchema: {
102
+ format: z.enum(["text", "json"]).default("text").describe("Formato de saida: text (legivel) ou json (estruturado)"),
103
+ cwd: z.string().optional().describe("Diretorio do projeto a analisar")
104
+ },
105
+ annotations: {
106
+ title: "Dead Code Detector",
107
+ readOnlyHint: true,
108
+ destructiveHint: false,
109
+ idempotentHint: true,
110
+ openWorldHint: false
111
+ }
112
+ },
113
+ async (params) => {
114
+ try {
115
+ const result = await dead({
116
+ format: params.format,
117
+ cwd: params.cwd
118
+ });
119
+ return { content: [{ type: "text", text: result }] };
120
+ } catch (error) {
121
+ return {
122
+ content: [
123
+ {
124
+ type: "text",
125
+ text: `Erro ao executar dead: ${error instanceof Error ? error.message : String(error)}`
126
+ }
127
+ ],
128
+ isError: true
129
+ };
130
+ }
131
+ }
132
+ );
133
+ server.registerTool(
134
+ "aitool_impact_analysis",
135
+ {
136
+ title: "Impact Analysis",
137
+ description: `Analisa o impacto de modificar um arquivo especifico.
138
+
139
+ ANALISA:
140
+ - UPSTREAM: Quem importa este arquivo (direto e indireto)
141
+ - DOWNSTREAM: O que este arquivo importa (direto e indireto)
142
+ - RISCOS: Arquivo critico, dependencias circulares, cadeia profunda
143
+ - SUGESTOES: O que verificar antes de modificar
144
+
145
+ PARAMETROS:
146
+ - target: Nome ou caminho do arquivo a analisar (obrigatorio)
147
+ - format: "text" (legivel) ou "json" (estruturado)
148
+ - cwd: Diretorio do projeto (default: diretorio atual)
149
+
150
+ O TARGET pode ser:
151
+ - Caminho completo: "src/components/Button.tsx"
152
+ - Caminho parcial: "components/Button"
153
+ - Nome do arquivo: "Button"
154
+
155
+ RETORNA:
156
+ - Categoria do arquivo target
157
+ - Lista de arquivos upstream (quem importa)
158
+ - Lista de arquivos downstream (o que importa)
159
+ - Alertas de risco com severidade
160
+ - Sugestoes de como proceder
161
+
162
+ EXEMPLO DE USO:
163
+ Chamar ANTES de modificar um arquivo para entender o impacto.
164
+ Usar para planejar refatoracoes seguras.`,
165
+ inputSchema: {
166
+ target: z.string().min(1).describe(
167
+ "Arquivo a analisar: caminho completo, parcial ou nome do arquivo"
168
+ ),
169
+ format: z.enum(["text", "json"]).default("text").describe("Formato de saida: text (legivel) ou json (estruturado)"),
170
+ cwd: z.string().optional().describe("Diretorio do projeto a analisar")
171
+ },
172
+ annotations: {
173
+ title: "Impact Analysis",
174
+ readOnlyHint: true,
175
+ destructiveHint: false,
176
+ idempotentHint: true,
177
+ openWorldHint: false
178
+ }
179
+ },
180
+ async (params) => {
181
+ try {
182
+ const result = await impact(params.target, {
183
+ format: params.format,
184
+ cwd: params.cwd
185
+ });
186
+ return { content: [{ type: "text", text: result }] };
187
+ } catch (error) {
188
+ return {
189
+ content: [
190
+ {
191
+ type: "text",
192
+ text: `Erro ao executar impact: ${error instanceof Error ? error.message : String(error)}`
193
+ }
194
+ ],
195
+ isError: true
196
+ };
197
+ }
198
+ }
199
+ );
200
+ server.registerTool(
201
+ "aitool_suggest_reads",
202
+ {
203
+ title: "Suggest Files to Read",
204
+ description: `Sugere arquivos que devem ser lidos ANTES de modificar um arquivo especifico.
205
+
206
+ PRIORIZA (nesta ordem):
207
+ 1. CRITICAL: Arquivos de tipos/interfaces usados pelo target
208
+ 2. HIGH: Dependencias diretas (arquivos importados pelo target)
209
+ 3. MEDIUM: Upstream (arquivos que importam o target)
210
+ 4. LOW: Testes relacionados
211
+
212
+ PARAMETROS:
213
+ - target: Nome ou caminho do arquivo que sera modificado (obrigatorio)
214
+ - limit: Numero maximo de sugestoes (default: 10, max: 50)
215
+ - cwd: Diretorio do projeto (default: diretorio atual)
216
+
217
+ O TARGET pode ser:
218
+ - Caminho completo: "src/components/Button.tsx"
219
+ - Caminho parcial: "components/Button"
220
+ - Nome do arquivo: "Button"
221
+
222
+ RETORNA:
223
+ - Lista ordenada de arquivos para ler
224
+ - Cada sugestao tem: path, categoria, razao, prioridade
225
+
226
+ EXEMPLO DE USO:
227
+ Chamar ANTES de modificar um arquivo para saber o que ler primeiro.
228
+ Util para entender o contexto completo antes de fazer mudancas.`,
229
+ inputSchema: {
230
+ target: z.string().min(1).describe(
231
+ "Arquivo que sera modificado: caminho completo, parcial ou nome"
232
+ ),
233
+ limit: z.number().int().min(1).max(50).default(10).describe("Numero maximo de sugestoes (default: 10)"),
234
+ cwd: z.string().optional().describe("Diretorio do projeto a analisar")
235
+ },
236
+ annotations: {
237
+ title: "Suggest Files to Read",
238
+ readOnlyHint: true,
239
+ destructiveHint: false,
240
+ idempotentHint: true,
241
+ openWorldHint: false
242
+ }
243
+ },
244
+ async (params) => {
245
+ try {
246
+ const result = await suggest(params.target, {
247
+ limit: params.limit,
248
+ cwd: params.cwd,
249
+ format: "text"
250
+ });
251
+ return { content: [{ type: "text", text: result }] };
252
+ } catch (error) {
253
+ return {
254
+ content: [
255
+ {
256
+ type: "text",
257
+ text: `Erro ao executar suggest: ${error instanceof Error ? error.message : String(error)}`
258
+ }
259
+ ],
260
+ isError: true
261
+ };
262
+ }
263
+ }
264
+ );
265
+ server.registerTool(
266
+ "aitool_file_context",
267
+ {
268
+ title: "Extract File Context",
269
+ description: `Extrai assinaturas de funcoes e tipos de um arquivo SEM a implementacao.
270
+
271
+ EXTRAI:
272
+ - IMPORTS: Todos os imports com specifiers e se sao type-only
273
+ - EXPORTS: Lista de tudo que e exportado
274
+ - FUNCOES: Nome, parametros (com tipos), retorno, async, arrow, JSDoc
275
+ - TIPOS: Interfaces, types e enums com suas definicoes completas
276
+
277
+ NAO INCLUI:
278
+ - Corpo das funcoes (implementacao)
279
+ - Logica interna
280
+ - Comentarios inline
281
+
282
+ PARAMETROS:
283
+ - target: Nome ou caminho do arquivo (obrigatorio)
284
+ - cwd: Diretorio do projeto (default: diretorio atual)
285
+
286
+ O TARGET pode ser:
287
+ - Caminho completo: "src/components/Button.tsx"
288
+ - Caminho parcial: "components/Button"
289
+ - Nome do arquivo: "Button"
290
+
291
+ RETORNA:
292
+ - Arquivo com categoria detectada
293
+ - Lista de imports estruturada
294
+ - Lista de exports
295
+ - Lista de funcoes com assinaturas completas
296
+ - Lista de tipos com definicoes
297
+
298
+ EXEMPLO DE USO:
299
+ Chamar para entender a API publica de um arquivo antes de usa-lo.
300
+ Util para saber quais funcoes/tipos um arquivo exporta.
301
+ Eficiente: retorna apenas assinaturas, nao o codigo completo.`,
302
+ inputSchema: {
303
+ target: z.string().min(1).describe(
304
+ "Arquivo para extrair contexto: caminho completo, parcial ou nome"
305
+ ),
306
+ cwd: z.string().optional().describe("Diretorio do projeto a analisar")
307
+ },
308
+ annotations: {
309
+ title: "Extract File Context",
310
+ readOnlyHint: true,
311
+ destructiveHint: false,
312
+ idempotentHint: true,
313
+ openWorldHint: false
314
+ }
315
+ },
316
+ async (params) => {
317
+ try {
318
+ const result = await context(params.target, {
319
+ cwd: params.cwd,
320
+ format: "text"
321
+ });
322
+ return { content: [{ type: "text", text: result }] };
323
+ } catch (error) {
324
+ return {
325
+ content: [
326
+ {
327
+ type: "text",
328
+ text: `Erro ao executar context: ${error instanceof Error ? error.message : String(error)}`
329
+ }
330
+ ],
331
+ isError: true
332
+ };
333
+ }
334
+ }
335
+ );
336
+ async function startMcpServer() {
337
+ const transport = new StdioServerTransport();
338
+ await server.connect(transport);
339
+ console.error(`[ai-tool] MCP server v${VERSION} running via stdio`);
340
+ }
341
+ export {
342
+ startMcpServer
343
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@justmpm/ai-tool",
3
- "version": "0.2.0",
3
+ "version": "0.3.1",
4
4
  "description": "Ferramenta de análise de dependências e impacto para projetos TypeScript/JavaScript. Usa Skott + Knip internamente.",
5
5
  "keywords": [
6
6
  "dependency-analysis",
@@ -43,8 +43,11 @@
43
43
  "typecheck": "tsc --noEmit"
44
44
  },
45
45
  "dependencies": {
46
+ "@modelcontextprotocol/sdk": "^1.25.3",
46
47
  "knip": "^5.44.0",
47
- "skott": "^0.35.2"
48
+ "skott": "^0.35.2",
49
+ "ts-morph": "^27.0.2",
50
+ "zod": "^3.25.76"
48
51
  },
49
52
  "devDependencies": {
50
53
  "@types/node": "^22.15.21",