@justmpm/ai-tool 0.9.0 → 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.
@@ -0,0 +1,145 @@
1
+ import {
2
+ findSimilar,
3
+ formatOutput,
4
+ parseCommandOptions,
5
+ readConfig
6
+ } from "./chunk-NVJXCSJF.js";
7
+
8
+ // src/commands/describe.ts
9
+ async function describe(query, options = {}) {
10
+ const { cwd, format } = parseCommandOptions(options);
11
+ if (!query || query.trim().length === 0) {
12
+ throw new Error("Query \xE9 obrigat\xF3ria. Exemplo: ai-tool describe 'autentica\xE7\xE3o'");
13
+ }
14
+ try {
15
+ const config = readConfig(cwd);
16
+ const normalizedQuery = query.toLowerCase().trim();
17
+ const candidates = Object.entries(config.areas).map(([id, area]) => ({
18
+ id,
19
+ name: area.name,
20
+ description: area.description || ""
21
+ }));
22
+ const matches = findAreaMatches(normalizedQuery, candidates, config);
23
+ const suggestions = [];
24
+ if (matches.length === 0) {
25
+ const similarAreaIds = findSimilar(
26
+ normalizedQuery,
27
+ candidates.map((c) => c.id),
28
+ { maxDistance: 2, limit: 3 }
29
+ );
30
+ const similarNames = findSimilar(
31
+ normalizedQuery,
32
+ candidates.map((c) => c.name),
33
+ { maxDistance: 2, limit: 3 }
34
+ );
35
+ suggestions.push(
36
+ ...similarAreaIds.map((id) => `\u2192 ai-tool describe ${id}`),
37
+ ...similarNames.map((name) => `\u2192 ai-tool describe "${name}"`)
38
+ );
39
+ }
40
+ const result = {
41
+ version: "1.0.0",
42
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
43
+ query,
44
+ areas: matches,
45
+ suggestions: suggestions.length > 0 ? suggestions : void 0
46
+ };
47
+ return formatOutput(result, format, formatDescribeText);
48
+ } catch (error) {
49
+ const message = error instanceof Error ? error.message : String(error);
50
+ throw new Error(`Erro ao executar describe: ${message}`);
51
+ }
52
+ }
53
+ function findAreaMatches(normalizedQuery, candidates, config) {
54
+ const matches = [];
55
+ for (const candidate of candidates) {
56
+ const searchableText = `${candidate.id} ${candidate.name} ${candidate.description}`.toLowerCase();
57
+ const hasDirectMatch = searchableText.includes(normalizedQuery);
58
+ const queryWords = normalizedQuery.split(/\s+/);
59
+ const allWordsMatch = queryWords.every((word) => searchableText.includes(word));
60
+ if (hasDirectMatch || allWordsMatch) {
61
+ const areaFiles = getAreaFiles(candidate.id, config);
62
+ const score = calculateRelevanceScore(normalizedQuery, searchableText);
63
+ matches.push({
64
+ id: candidate.id,
65
+ name: candidate.name,
66
+ description: candidate.description || "Sem descri\xE7\xE3o",
67
+ files: areaFiles,
68
+ fileCount: areaFiles.length,
69
+ score
70
+ });
71
+ }
72
+ }
73
+ return matches.sort((a, b) => a.score - b.score);
74
+ }
75
+ function getAreaFiles(areaId, config) {
76
+ const files = [];
77
+ const areaConfig = config.areas[areaId];
78
+ if (areaConfig?.patterns) {
79
+ files.push(`[Use 'ai-tool area ${areaId}' para ver arquivos completos]`);
80
+ }
81
+ return files;
82
+ }
83
+ function calculateRelevanceScore(query, text) {
84
+ if (text.includes(query)) {
85
+ return 0;
86
+ }
87
+ const queryWords = query.split(/\s+/).filter(Boolean);
88
+ const allWordsPresent = queryWords.every((word) => text.includes(word));
89
+ if (allWordsPresent) {
90
+ return 1;
91
+ }
92
+ return 10;
93
+ }
94
+ function formatDescribeText(result) {
95
+ let out = "";
96
+ if (result.areas.length === 0) {
97
+ out += `\u274C Nenhuma \xE1rea encontrada para: "${result.query}"
98
+
99
+ `;
100
+ if (result.suggestions && result.suggestions.length > 0) {
101
+ out += `\u{1F4A1} Voc\xEA quis dizer?
102
+ `;
103
+ for (const suggestion of result.suggestions) {
104
+ out += ` ${suggestion}
105
+ `;
106
+ }
107
+ out += `
108
+ `;
109
+ }
110
+ out += `\u{1F4D6} Dica: Use 'ai-tool areas' para listar todas as \xE1reas dispon\xEDveis`;
111
+ return out;
112
+ }
113
+ out += `\u{1F50D} Busca: "${result.query}"
114
+
115
+ `;
116
+ for (const area of result.areas) {
117
+ out += `## ${area.name} (${area.id})
118
+ `;
119
+ out += `${area.description}
120
+ `;
121
+ out += `\u{1F4C1} ${area.fileCount} arquivo(s)
122
+
123
+ `;
124
+ if (area.files.length > 0) {
125
+ out += `Arquivos:
126
+ `;
127
+ for (const file of area.files) {
128
+ out += ` \u2022 ${file}
129
+ `;
130
+ }
131
+ out += "\n";
132
+ }
133
+ }
134
+ out += `\u{1F4D6} Pr\xF3ximos passos:
135
+ `;
136
+ out += ` \u2192 ai-tool area <id> - ver detalhes de uma \xE1rea
137
+ `;
138
+ out += ` \u2192 ai-tool context --area=<id> - contexto completo de uma \xE1rea
139
+ `;
140
+ return out;
141
+ }
142
+
143
+ export {
144
+ describe
145
+ };
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,
@@ -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-L24EN4AN.js");
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.");
@@ -1,3 +1,6 @@
1
+ import {
2
+ describe
3
+ } from "./chunk-CACALWH5.js";
1
4
  import {
2
5
  VERSION,
3
6
  area,
@@ -7,13 +10,9 @@ import {
7
10
  context,
8
11
  dead,
9
12
  find,
10
- findSimilar,
11
- formatOutput,
12
13
  functions,
13
14
  impact,
14
15
  map,
15
- parseCommandOptions,
16
- readConfig,
17
16
  suggest
18
17
  } from "./chunk-NVJXCSJF.js";
19
18
 
@@ -23,143 +22,6 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
23
22
 
24
23
  // src/mcp/tools.ts
25
24
  import { z } from "zod";
26
-
27
- // src/commands/describe.ts
28
- async function describe(query, options = {}) {
29
- const { cwd, format } = parseCommandOptions(options);
30
- if (!query || query.trim().length === 0) {
31
- throw new Error("Query \xE9 obrigat\xF3ria. Exemplo: ai-tool describe 'autentica\xE7\xE3o'");
32
- }
33
- try {
34
- const config = readConfig(cwd);
35
- const normalizedQuery = query.toLowerCase().trim();
36
- const candidates = Object.entries(config.areas).map(([id, area2]) => ({
37
- id,
38
- name: area2.name,
39
- description: area2.description || ""
40
- }));
41
- const matches = findAreaMatches(normalizedQuery, candidates, config);
42
- const suggestions = [];
43
- if (matches.length === 0) {
44
- const similarAreaIds = findSimilar(
45
- normalizedQuery,
46
- candidates.map((c) => c.id),
47
- { maxDistance: 2, limit: 3 }
48
- );
49
- const similarNames = findSimilar(
50
- normalizedQuery,
51
- candidates.map((c) => c.name),
52
- { maxDistance: 2, limit: 3 }
53
- );
54
- suggestions.push(
55
- ...similarAreaIds.map((id) => `\u2192 ai-tool describe ${id}`),
56
- ...similarNames.map((name) => `\u2192 ai-tool describe "${name}"`)
57
- );
58
- }
59
- const result = {
60
- version: "1.0.0",
61
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
62
- query,
63
- areas: matches,
64
- suggestions: suggestions.length > 0 ? suggestions : void 0
65
- };
66
- return formatOutput(result, format, formatDescribeText);
67
- } catch (error) {
68
- const message = error instanceof Error ? error.message : String(error);
69
- throw new Error(`Erro ao executar describe: ${message}`);
70
- }
71
- }
72
- function findAreaMatches(normalizedQuery, candidates, config) {
73
- const matches = [];
74
- for (const candidate of candidates) {
75
- const searchableText = `${candidate.id} ${candidate.name} ${candidate.description}`.toLowerCase();
76
- const hasDirectMatch = searchableText.includes(normalizedQuery);
77
- const queryWords = normalizedQuery.split(/\s+/);
78
- const allWordsMatch = queryWords.every((word) => searchableText.includes(word));
79
- if (hasDirectMatch || allWordsMatch) {
80
- const areaFiles = getAreaFiles(candidate.id, config);
81
- const score = calculateRelevanceScore(normalizedQuery, searchableText);
82
- matches.push({
83
- id: candidate.id,
84
- name: candidate.name,
85
- description: candidate.description || "Sem descri\xE7\xE3o",
86
- files: areaFiles,
87
- fileCount: areaFiles.length,
88
- score
89
- });
90
- }
91
- }
92
- return matches.sort((a, b) => a.score - b.score);
93
- }
94
- function getAreaFiles(areaId, config) {
95
- const files = [];
96
- const areaConfig = config.areas[areaId];
97
- if (areaConfig?.patterns) {
98
- files.push(`[Use 'ai-tool area ${areaId}' para ver arquivos completos]`);
99
- }
100
- return files;
101
- }
102
- function calculateRelevanceScore(query, text) {
103
- if (text.includes(query)) {
104
- return 0;
105
- }
106
- const queryWords = query.split(/\s+/).filter(Boolean);
107
- const allWordsPresent = queryWords.every((word) => text.includes(word));
108
- if (allWordsPresent) {
109
- return 1;
110
- }
111
- return 10;
112
- }
113
- function formatDescribeText(result) {
114
- let out = "";
115
- if (result.areas.length === 0) {
116
- out += `\u274C Nenhuma \xE1rea encontrada para: "${result.query}"
117
-
118
- `;
119
- if (result.suggestions && result.suggestions.length > 0) {
120
- out += `\u{1F4A1} Voc\xEA quis dizer?
121
- `;
122
- for (const suggestion of result.suggestions) {
123
- out += ` ${suggestion}
124
- `;
125
- }
126
- out += `
127
- `;
128
- }
129
- out += `\u{1F4D6} Dica: Use 'ai-tool areas' para listar todas as \xE1reas dispon\xEDveis`;
130
- return out;
131
- }
132
- out += `\u{1F50D} Busca: "${result.query}"
133
-
134
- `;
135
- for (const area2 of result.areas) {
136
- out += `## ${area2.name} (${area2.id})
137
- `;
138
- out += `${area2.description}
139
- `;
140
- out += `\u{1F4C1} ${area2.fileCount} arquivo(s)
141
-
142
- `;
143
- if (area2.files.length > 0) {
144
- out += `Arquivos:
145
- `;
146
- for (const file of area2.files) {
147
- out += ` \u2022 ${file}
148
- `;
149
- }
150
- out += "\n";
151
- }
152
- }
153
- out += `\u{1F4D6} Pr\xF3ximos passos:
154
- `;
155
- out += ` \u2192 ai-tool area <id> - ver detalhes de uma \xE1rea
156
- `;
157
- out += ` \u2192 ai-tool context --area=<id> - contexto completo de uma \xE1rea
158
- `;
159
- return out;
160
- }
161
-
162
- // src/mcp/tools.ts
163
25
  function registerAllTools(server2) {
164
26
  server2.registerTool(
165
27
  "aitool_project_map",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@justmpm/ai-tool",
3
- "version": "0.9.0",
3
+ "version": "0.9.1",
4
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",
@@ -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
  },