@justmpm/ai-tool 3.23.0 → 4.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/{chunk-WTRV35AO.js → chunk-BFOWLQIL.js} +23 -581
- package/dist/chunk-OQSQWBJV.js +387 -0
- package/dist/cli.js +4 -58
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/{server-3HLEATUD.js → server-QFWWHDJY.js} +2 -157
- package/package.json +4 -2
- package/dist/chunk-4Z6PUAFR.js +0 -2185
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
import {
|
|
2
|
+
detectFileAreas,
|
|
3
|
+
findSimilar,
|
|
4
|
+
formatOutput,
|
|
5
|
+
getProjectIndexArtifact,
|
|
6
|
+
getWorkspaceFiles,
|
|
7
|
+
hint,
|
|
8
|
+
isFileIgnored,
|
|
9
|
+
nextSteps,
|
|
10
|
+
parseCommandOptions,
|
|
11
|
+
readConfig
|
|
12
|
+
} from "./chunk-BFOWLQIL.js";
|
|
13
|
+
|
|
14
|
+
// src/commands/describe.ts
|
|
15
|
+
var STOPWORDS = /* @__PURE__ */ new Set([
|
|
16
|
+
// PT-BR
|
|
17
|
+
"de",
|
|
18
|
+
"da",
|
|
19
|
+
"do",
|
|
20
|
+
"das",
|
|
21
|
+
"dos",
|
|
22
|
+
"para",
|
|
23
|
+
"com",
|
|
24
|
+
"em",
|
|
25
|
+
"uma",
|
|
26
|
+
"um",
|
|
27
|
+
"o",
|
|
28
|
+
"a",
|
|
29
|
+
"os",
|
|
30
|
+
"as",
|
|
31
|
+
"no",
|
|
32
|
+
"na",
|
|
33
|
+
"nos",
|
|
34
|
+
"nas",
|
|
35
|
+
"pelo",
|
|
36
|
+
"pela",
|
|
37
|
+
"que",
|
|
38
|
+
"e",
|
|
39
|
+
"ou",
|
|
40
|
+
"se",
|
|
41
|
+
"ao",
|
|
42
|
+
"aos",
|
|
43
|
+
// EN
|
|
44
|
+
"the",
|
|
45
|
+
"of",
|
|
46
|
+
"in",
|
|
47
|
+
"for",
|
|
48
|
+
"with",
|
|
49
|
+
"on",
|
|
50
|
+
"at",
|
|
51
|
+
"to",
|
|
52
|
+
"and",
|
|
53
|
+
"or",
|
|
54
|
+
"is",
|
|
55
|
+
"are",
|
|
56
|
+
"was",
|
|
57
|
+
"by",
|
|
58
|
+
"an"
|
|
59
|
+
]);
|
|
60
|
+
function removeStopwords(words) {
|
|
61
|
+
const filtered = words.filter((w) => !STOPWORDS.has(w) && w.length > 1);
|
|
62
|
+
return filtered.length > 0 ? filtered : words;
|
|
63
|
+
}
|
|
64
|
+
function calculatePartialScore(queryWords, searchableText) {
|
|
65
|
+
if (queryWords.length === 0) return 1;
|
|
66
|
+
const fullQuery = queryWords.join(" ");
|
|
67
|
+
if (searchableText.includes(fullQuery)) return 0;
|
|
68
|
+
let found = 0;
|
|
69
|
+
for (const word of queryWords) {
|
|
70
|
+
if (searchableText.includes(word)) {
|
|
71
|
+
found++;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return 1 - found / queryWords.length;
|
|
75
|
+
}
|
|
76
|
+
function buildAreaFileMap(allFiles, config) {
|
|
77
|
+
const map = /* @__PURE__ */ new Map();
|
|
78
|
+
for (const filePath of allFiles) {
|
|
79
|
+
if (isFileIgnored(filePath, config)) continue;
|
|
80
|
+
const fileAreas = detectFileAreas(filePath, config);
|
|
81
|
+
for (const areaId of fileAreas) {
|
|
82
|
+
if (!map.has(areaId)) map.set(areaId, []);
|
|
83
|
+
map.get(areaId).push(filePath);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return map;
|
|
87
|
+
}
|
|
88
|
+
var GENERIC_PARAMS = /* @__PURE__ */ new Set([
|
|
89
|
+
"id",
|
|
90
|
+
"data",
|
|
91
|
+
"item",
|
|
92
|
+
"row",
|
|
93
|
+
"key",
|
|
94
|
+
"val",
|
|
95
|
+
"value",
|
|
96
|
+
"obj",
|
|
97
|
+
"obj",
|
|
98
|
+
"arr",
|
|
99
|
+
"list",
|
|
100
|
+
"map",
|
|
101
|
+
"set",
|
|
102
|
+
"x",
|
|
103
|
+
"y",
|
|
104
|
+
"z",
|
|
105
|
+
"a",
|
|
106
|
+
"b",
|
|
107
|
+
"c",
|
|
108
|
+
"n",
|
|
109
|
+
"i",
|
|
110
|
+
"j",
|
|
111
|
+
"k",
|
|
112
|
+
"err",
|
|
113
|
+
"e",
|
|
114
|
+
"res",
|
|
115
|
+
"req",
|
|
116
|
+
"next"
|
|
117
|
+
]);
|
|
118
|
+
function buildSearchableTextAndMatches(candidate, config, areaFileMap, index, queryWords) {
|
|
119
|
+
const symbolMatches = [];
|
|
120
|
+
const metadata = `${candidate.id} ${candidate.name} ${candidate.description}`;
|
|
121
|
+
const keywords = config.areas[candidate.id]?.keywords?.join(" ") ?? "";
|
|
122
|
+
const areaFiles = areaFileMap.get(candidate.id) ?? [];
|
|
123
|
+
const fileNames = areaFiles.map((f) => {
|
|
124
|
+
const name = f.split("/").pop() ?? "";
|
|
125
|
+
return name.replace(/\.(tsx?|jsx?|mjs|cjs)$/, "");
|
|
126
|
+
}).join(" ");
|
|
127
|
+
const symbolNames = [];
|
|
128
|
+
const symbolSignatures = [];
|
|
129
|
+
const symbolParams = [];
|
|
130
|
+
const symbolReturnTypes = [];
|
|
131
|
+
for (const filePath of areaFiles) {
|
|
132
|
+
const fileData = index.files[filePath];
|
|
133
|
+
if (fileData?.symbols) {
|
|
134
|
+
for (const symbol of fileData.symbols) {
|
|
135
|
+
if (!symbol.isExported) continue;
|
|
136
|
+
symbolNames.push(symbol.name);
|
|
137
|
+
const MAX_SIGNATURE_CHARS = 200;
|
|
138
|
+
const sig = symbol.signature.length > MAX_SIGNATURE_CHARS ? symbol.signature.slice(0, MAX_SIGNATURE_CHARS) + "..." : symbol.signature;
|
|
139
|
+
symbolSignatures.push(sig);
|
|
140
|
+
if (symbol.params && symbol.params.length > 0) {
|
|
141
|
+
const filteredParams = symbol.params.filter((p) => !GENERIC_PARAMS.has(p));
|
|
142
|
+
const paramsText = filteredParams.slice(0, 10).join(" ");
|
|
143
|
+
if (paramsText) {
|
|
144
|
+
symbolParams.push(paramsText);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
if (symbol.returnType) {
|
|
148
|
+
symbolReturnTypes.push(symbol.returnType);
|
|
149
|
+
}
|
|
150
|
+
for (const word of queryWords) {
|
|
151
|
+
if (symbol.signature.toLowerCase().includes(word)) {
|
|
152
|
+
const cleanSig = symbol.signature.replace(/export\s+/g, "").replace(/\s+/g, " ");
|
|
153
|
+
symbolMatches.push({
|
|
154
|
+
name: symbol.name,
|
|
155
|
+
file: filePath,
|
|
156
|
+
signature: cleanSig,
|
|
157
|
+
matchType: "signature",
|
|
158
|
+
matchedText: word
|
|
159
|
+
});
|
|
160
|
+
} else if (symbol.params?.some((p) => p.toLowerCase().includes(word))) {
|
|
161
|
+
const cleanSig = symbol.signature.replace(/export\s+/g, "").replace(/\s+/g, " ");
|
|
162
|
+
symbolMatches.push({
|
|
163
|
+
name: symbol.name,
|
|
164
|
+
file: filePath,
|
|
165
|
+
signature: cleanSig,
|
|
166
|
+
matchType: "params",
|
|
167
|
+
matchedText: word
|
|
168
|
+
});
|
|
169
|
+
} else if (symbol.returnType?.toLowerCase().includes(word)) {
|
|
170
|
+
const cleanSig = symbol.signature.replace(/export\s+/g, "").replace(/\s+/g, " ");
|
|
171
|
+
symbolMatches.push({
|
|
172
|
+
name: symbol.name,
|
|
173
|
+
file: filePath,
|
|
174
|
+
signature: cleanSig,
|
|
175
|
+
matchType: "returnType",
|
|
176
|
+
matchedText: word
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
const searchableText = [
|
|
184
|
+
metadata,
|
|
185
|
+
keywords,
|
|
186
|
+
fileNames,
|
|
187
|
+
symbolNames.join(" "),
|
|
188
|
+
symbolSignatures.join(" "),
|
|
189
|
+
symbolParams.join(" "),
|
|
190
|
+
symbolReturnTypes.join(" ")
|
|
191
|
+
].join(" ").toLowerCase();
|
|
192
|
+
return { searchableText, symbolMatches };
|
|
193
|
+
}
|
|
194
|
+
async function findAreaMatches(normalizedQuery, candidates, config, cwd) {
|
|
195
|
+
const allFiles = await getWorkspaceFiles(cwd);
|
|
196
|
+
const artifact = await getProjectIndexArtifact(cwd, { useCache: true });
|
|
197
|
+
const index = artifact.index;
|
|
198
|
+
const areaFileMap = buildAreaFileMap(allFiles, config);
|
|
199
|
+
const queryWords = removeStopwords(normalizedQuery.split(/\s+/));
|
|
200
|
+
const matches = [];
|
|
201
|
+
for (const candidate of candidates) {
|
|
202
|
+
const { searchableText, symbolMatches } = buildSearchableTextAndMatches(
|
|
203
|
+
candidate,
|
|
204
|
+
config,
|
|
205
|
+
areaFileMap,
|
|
206
|
+
index,
|
|
207
|
+
queryWords
|
|
208
|
+
);
|
|
209
|
+
const score = calculatePartialScore(queryWords, searchableText);
|
|
210
|
+
if (score < 0.6) {
|
|
211
|
+
const areaFiles = areaFileMap.get(candidate.id) ?? [];
|
|
212
|
+
const seen = /* @__PURE__ */ new Set();
|
|
213
|
+
const uniqueSymbolMatches = symbolMatches.filter((m) => {
|
|
214
|
+
const key = `${m.file}:${m.signature}`;
|
|
215
|
+
if (seen.has(key)) return false;
|
|
216
|
+
seen.add(key);
|
|
217
|
+
return true;
|
|
218
|
+
});
|
|
219
|
+
matches.push({
|
|
220
|
+
id: candidate.id,
|
|
221
|
+
name: candidate.name,
|
|
222
|
+
description: candidate.description || "Sem descricao",
|
|
223
|
+
files: areaFiles,
|
|
224
|
+
fileCount: areaFiles.length,
|
|
225
|
+
score,
|
|
226
|
+
symbolMatches: uniqueSymbolMatches.length > 0 ? uniqueSymbolMatches : void 0
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
return matches.sort((a, b) => a.score - b.score);
|
|
231
|
+
}
|
|
232
|
+
async function describe(query, options = {}) {
|
|
233
|
+
const { cwd, format } = parseCommandOptions(options);
|
|
234
|
+
const ctx = options.ctx || "cli";
|
|
235
|
+
if (!query || query.trim().length === 0) {
|
|
236
|
+
throw new Error("Query \xE9 obrigat\xF3ria. Exemplo: ai-tool describe 'autentica\xE7\xE3o'");
|
|
237
|
+
}
|
|
238
|
+
try {
|
|
239
|
+
const config = readConfig(cwd);
|
|
240
|
+
const hasAreas = Object.keys(config.areas).length > 0;
|
|
241
|
+
if (!hasAreas) {
|
|
242
|
+
let out = `\u26A0\uFE0F Nenhuma area configurada neste projeto.
|
|
243
|
+
|
|
244
|
+
`;
|
|
245
|
+
out += `O comando describe busca em areas configuradas.
|
|
246
|
+
`;
|
|
247
|
+
out += `Para configurar areas:
|
|
248
|
+
`;
|
|
249
|
+
out += ` 1. ${hint("areas_init", ctx)} - gerar arquivo de configuracao
|
|
250
|
+
`;
|
|
251
|
+
out += ` 2. Edite .analyze/areas.config.json com as areas do projeto
|
|
252
|
+
|
|
253
|
+
`;
|
|
254
|
+
out += `Enquanto isso, use:
|
|
255
|
+
`;
|
|
256
|
+
out += ` \u2192 ${hint("find", ctx)} - buscar simbolos no codigo
|
|
257
|
+
`;
|
|
258
|
+
out += ` \u2192 ${hint("map", ctx)} - ver estrutura do projeto
|
|
259
|
+
`;
|
|
260
|
+
return out;
|
|
261
|
+
}
|
|
262
|
+
const normalizedQuery = query.toLowerCase().trim();
|
|
263
|
+
const candidates = Object.entries(config.areas).map(([id, area]) => ({
|
|
264
|
+
id,
|
|
265
|
+
name: area.name,
|
|
266
|
+
description: area.description || ""
|
|
267
|
+
}));
|
|
268
|
+
const matches = await findAreaMatches(normalizedQuery, candidates, config, cwd);
|
|
269
|
+
const suggestions = [];
|
|
270
|
+
if (matches.length === 0) {
|
|
271
|
+
const similarAreaIds = findSimilar(
|
|
272
|
+
normalizedQuery,
|
|
273
|
+
candidates.map((c) => c.id),
|
|
274
|
+
{ maxDistance: 2, limit: 3 }
|
|
275
|
+
);
|
|
276
|
+
const similarNames = findSimilar(
|
|
277
|
+
normalizedQuery,
|
|
278
|
+
candidates.map((c) => c.name),
|
|
279
|
+
{ maxDistance: 2, limit: 3 }
|
|
280
|
+
);
|
|
281
|
+
suggestions.push(
|
|
282
|
+
...similarAreaIds.map((id) => `\u2192 ${hint("describe", ctx, { "<termo>": id })}`),
|
|
283
|
+
...similarNames.map((name) => `\u2192 ${hint("describe", ctx, { "<termo>": `"${name}"` })}`)
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
const result = {
|
|
287
|
+
version: "1.0.0",
|
|
288
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
289
|
+
query,
|
|
290
|
+
areas: matches,
|
|
291
|
+
suggestions: suggestions.length > 0 ? suggestions : void 0
|
|
292
|
+
};
|
|
293
|
+
return formatOutput(result, format, (r) => formatDescribeText(r, ctx));
|
|
294
|
+
} catch (error) {
|
|
295
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
296
|
+
throw new Error(`Erro ao executar describe: ${message}`);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
function formatDescribeText(result, ctx = "cli") {
|
|
300
|
+
let out = "";
|
|
301
|
+
if (result.areas.length === 0) {
|
|
302
|
+
out += `\u274C Nenhuma area encontrada para: "${result.query}"
|
|
303
|
+
|
|
304
|
+
`;
|
|
305
|
+
if (result.suggestions && result.suggestions.length > 0) {
|
|
306
|
+
out += `\u{1F4A1} Voce quis dizer?
|
|
307
|
+
`;
|
|
308
|
+
for (const suggestion of result.suggestions) {
|
|
309
|
+
out += ` ${suggestion}
|
|
310
|
+
`;
|
|
311
|
+
}
|
|
312
|
+
out += `
|
|
313
|
+
`;
|
|
314
|
+
}
|
|
315
|
+
out += `\u{1F4D6} Dicas:
|
|
316
|
+
`;
|
|
317
|
+
out += ` \u2192 ${hint("areas", ctx)} - listar todas as areas disponiveis
|
|
318
|
+
`;
|
|
319
|
+
out += ` \u2192 ${hint("find", ctx)} - buscar simbolos por nome
|
|
320
|
+
`;
|
|
321
|
+
return out;
|
|
322
|
+
}
|
|
323
|
+
out += `\u{1F50D} Busca: "${result.query}"
|
|
324
|
+
|
|
325
|
+
`;
|
|
326
|
+
for (const area of result.areas) {
|
|
327
|
+
out += `## ${area.name} (${area.id})
|
|
328
|
+
`;
|
|
329
|
+
out += `${area.description}
|
|
330
|
+
`;
|
|
331
|
+
out += `\u{1F4C1} ${area.fileCount} arquivo(s)
|
|
332
|
+
`;
|
|
333
|
+
if (area.symbolMatches && area.symbolMatches.length > 0) {
|
|
334
|
+
out += `
|
|
335
|
+
\u{1F517} Simbolos que correspondem a busca:
|
|
336
|
+
`;
|
|
337
|
+
const byFile = /* @__PURE__ */ new Map();
|
|
338
|
+
for (const match of area.symbolMatches) {
|
|
339
|
+
if (!byFile.has(match.file)) byFile.set(match.file, []);
|
|
340
|
+
byFile.get(match.file).push(match);
|
|
341
|
+
}
|
|
342
|
+
const MAX_SYMBOLS = 5;
|
|
343
|
+
let count = 0;
|
|
344
|
+
for (const [file, matches] of byFile) {
|
|
345
|
+
for (const match of matches) {
|
|
346
|
+
if (count >= MAX_SYMBOLS) break;
|
|
347
|
+
const matchLabel = match.matchType === "signature" ? "\u21B3" : match.matchType === "params" ? "\u2192 (param)" : "\u2192 (return)";
|
|
348
|
+
out += ` ${matchLabel} ${file}
|
|
349
|
+
`;
|
|
350
|
+
out += ` ${match.signature}
|
|
351
|
+
`;
|
|
352
|
+
count++;
|
|
353
|
+
}
|
|
354
|
+
if (count >= MAX_SYMBOLS) break;
|
|
355
|
+
}
|
|
356
|
+
if (area.symbolMatches.length > MAX_SYMBOLS) {
|
|
357
|
+
out += ` ... e mais ${area.symbolMatches.length - MAX_SYMBOLS} simbolo(s)
|
|
358
|
+
`;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
out += "\n";
|
|
362
|
+
if (area.files.length > 0) {
|
|
363
|
+
const MAX_FILES = 5;
|
|
364
|
+
const filesToShow = area.files.slice(0, MAX_FILES);
|
|
365
|
+
const remaining = area.files.length - filesToShow.length;
|
|
366
|
+
out += `Arquivos:
|
|
367
|
+
`;
|
|
368
|
+
for (const file of filesToShow) {
|
|
369
|
+
out += ` \u2022 ${file}
|
|
370
|
+
`;
|
|
371
|
+
}
|
|
372
|
+
if (remaining > 0) {
|
|
373
|
+
out += ` ... e mais ${remaining} arquivo(s)
|
|
374
|
+
`;
|
|
375
|
+
out += ` \u2192 ${hint("area", ctx, { "<nome>": area.id })} - ver todos
|
|
376
|
+
`;
|
|
377
|
+
}
|
|
378
|
+
out += "\n";
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
out += nextSteps("describe", ctx);
|
|
382
|
+
return out;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
export {
|
|
386
|
+
describe
|
|
387
|
+
};
|
package/dist/cli.js
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
depsApi,
|
|
4
|
-
depsInfo,
|
|
5
|
-
depsSearch,
|
|
6
3
|
describe
|
|
7
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-OQSQWBJV.js";
|
|
8
5
|
import {
|
|
9
6
|
VERSION,
|
|
10
7
|
area,
|
|
@@ -20,7 +17,7 @@ import {
|
|
|
20
17
|
impact,
|
|
21
18
|
map,
|
|
22
19
|
suggest
|
|
23
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-BFOWLQIL.js";
|
|
24
21
|
|
|
25
22
|
// src/cli.ts
|
|
26
23
|
import { resolve } from "path";
|
|
@@ -65,12 +62,7 @@ CHANGES:
|
|
|
65
62
|
changes --unstaged Mudancas no working directory
|
|
66
63
|
changes --file=src/types/auth.ts Detalhar um arquivo especifico
|
|
67
64
|
|
|
68
|
-
|
|
69
|
-
deps info <pacote> Informacoes gerais de um pacote instalado
|
|
70
|
-
deps api <pacote> API publica (funcoes, tipos, interfaces)
|
|
71
|
-
deps search <pacote> <termo> Busca simbolo especifico no pacote
|
|
72
|
-
|
|
73
|
-
MODOS:
|
|
65
|
+
MODOS:
|
|
74
66
|
--mcp Inicia servidor MCP para integracao com Claude Desktop
|
|
75
67
|
|
|
76
68
|
OPCOES:
|
|
@@ -131,7 +123,7 @@ async function main() {
|
|
|
131
123
|
}
|
|
132
124
|
}
|
|
133
125
|
if (flags.mcp) {
|
|
134
|
-
const { startMcpServer } = await import("./server-
|
|
126
|
+
const { startMcpServer } = await import("./server-QFWWHDJY.js");
|
|
135
127
|
await startMcpServer();
|
|
136
128
|
return;
|
|
137
129
|
}
|
|
@@ -262,52 +254,6 @@ async function main() {
|
|
|
262
254
|
file: flags.file
|
|
263
255
|
});
|
|
264
256
|
break;
|
|
265
|
-
case "deps":
|
|
266
|
-
if (!target) {
|
|
267
|
-
console.error("Erro: subcomando deps obrigatorio");
|
|
268
|
-
console.error(" Exemplo: ai-tool deps info @mui/material");
|
|
269
|
-
console.error(" Exemplo: ai-tool deps api zustand");
|
|
270
|
-
console.error(" Exemplo: ai-tool deps search @mui/material Button");
|
|
271
|
-
process.exit(1);
|
|
272
|
-
}
|
|
273
|
-
switch (target) {
|
|
274
|
-
case "info": {
|
|
275
|
-
const pkg = positional[2];
|
|
276
|
-
if (!pkg) {
|
|
277
|
-
console.error("Erro: nome do pacote obrigatorio para deps info");
|
|
278
|
-
console.error(" Exemplo: ai-tool deps info @mui/material");
|
|
279
|
-
process.exit(1);
|
|
280
|
-
}
|
|
281
|
-
result = await depsInfo(pkg, { format, cwd, ctx: "cli" });
|
|
282
|
-
break;
|
|
283
|
-
}
|
|
284
|
-
case "api": {
|
|
285
|
-
const pkg = positional[2];
|
|
286
|
-
if (!pkg) {
|
|
287
|
-
console.error("Erro: nome do pacote obrigatorio para deps api");
|
|
288
|
-
console.error(" Exemplo: ai-tool deps api zustand");
|
|
289
|
-
process.exit(1);
|
|
290
|
-
}
|
|
291
|
-
result = await depsApi(pkg, { format, cwd, limit: flags.limit ? Number(flags.limit) : void 0, kind: flags.kind, ctx: "cli" });
|
|
292
|
-
break;
|
|
293
|
-
}
|
|
294
|
-
case "search": {
|
|
295
|
-
const pkg = positional[2];
|
|
296
|
-
const query = positional[3];
|
|
297
|
-
if (!pkg || !query) {
|
|
298
|
-
console.error("Erro: pacote e termo de busca obrigatorios para deps search");
|
|
299
|
-
console.error(" Exemplo: ai-tool deps search @mui/material Button");
|
|
300
|
-
process.exit(1);
|
|
301
|
-
}
|
|
302
|
-
result = await depsSearch(pkg, query, { format, cwd, kind: flags.kind, ctx: "cli" });
|
|
303
|
-
break;
|
|
304
|
-
}
|
|
305
|
-
default:
|
|
306
|
-
console.error(`Subcomando deps desconhecido: ${target}`);
|
|
307
|
-
console.error(" Subcomandos disponiveis: info, api, search");
|
|
308
|
-
process.exit(1);
|
|
309
|
-
}
|
|
310
|
-
break;
|
|
311
257
|
default:
|
|
312
258
|
console.error(`\u274C Comando desconhecido: ${command}`);
|
|
313
259
|
console.error(" Use 'ai-tool --help' para ver comandos dispon\xEDveis.");
|
package/dist/index.d.ts
CHANGED
|
@@ -568,7 +568,7 @@ declare function nextSteps(command: string, ctx: HintContext): string;
|
|
|
568
568
|
* @param extra - Informação extra sobre o erro
|
|
569
569
|
* @returns String formatada com dica de recuperação
|
|
570
570
|
*/
|
|
571
|
-
type RecoveryErrorType = "file_not_found" | "area_not_found" | "no_results" | "no_firebase" | "no_areas_configured" | "symbol_not_found" | "
|
|
571
|
+
type RecoveryErrorType = "file_not_found" | "area_not_found" | "no_results" | "no_firebase" | "no_areas_configured" | "symbol_not_found" | "index_failed" | "generic";
|
|
572
572
|
declare function recoveryHint(errorType: RecoveryErrorType, ctx: HintContext, _extra?: {
|
|
573
573
|
command?: string;
|
|
574
574
|
}): string;
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
|
-
depsApi,
|
|
3
|
-
depsInfo,
|
|
4
|
-
depsSearch,
|
|
5
2
|
describe
|
|
6
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-OQSQWBJV.js";
|
|
7
4
|
import {
|
|
8
5
|
VERSION,
|
|
9
6
|
area,
|
|
@@ -19,7 +16,7 @@ import {
|
|
|
19
16
|
map,
|
|
20
17
|
recoveryHint,
|
|
21
18
|
suggest
|
|
22
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-BFOWLQIL.js";
|
|
23
20
|
|
|
24
21
|
// src/mcp/server.ts
|
|
25
22
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
@@ -626,158 +623,6 @@ Se os entries nao mostrarem descricoes, execute find { query: "<qualquer simbolo
|
|
|
626
623
|
const hint = recoveryHint("generic", "mcp");
|
|
627
624
|
return {
|
|
628
625
|
content: [{ type: "text", text: `Erro ao executar changes: ${msg}
|
|
629
|
-
${hint}` }],
|
|
630
|
-
isError: true
|
|
631
|
-
};
|
|
632
|
-
}
|
|
633
|
-
}
|
|
634
|
-
);
|
|
635
|
-
server2.registerTool(
|
|
636
|
-
"aitool_deps_info",
|
|
637
|
-
{
|
|
638
|
-
title: "Package Info",
|
|
639
|
-
description: `Informacoes de um pacote instalado no node_modules: versao, descricao, entry points, dependencias.
|
|
640
|
-
Le o package.json REAL do node_modules (versao instalada, nao do registry).
|
|
641
|
-
|
|
642
|
-
Quando usar: descobrir versao instalada de uma lib, encontrar entry points, ver dependencias peer, verificar se o pacote tem types.
|
|
643
|
-
NAO use para: ver a API publica (use deps_api) ou buscar simbolo especifico (use deps_search).
|
|
644
|
-
|
|
645
|
-
Workflow: deps_info (overview) -> deps_api (API completa) -> deps_search (simbolo especifico)
|
|
646
|
-
Dica: Se o pacote nao estiver instalado, instale-o antes (npm/yarn/bun/pnpm).`,
|
|
647
|
-
inputSchema: {
|
|
648
|
-
package: z.string().min(1).describe("Nome do pacote (ex: @mui/material, zustand)"),
|
|
649
|
-
format: z.enum(["text", "json"]).default("text").describe("Formato de saida: text (legivel) ou json (estruturado)"),
|
|
650
|
-
cwd: z.string().optional().describe("Diretorio do projeto a analisar")
|
|
651
|
-
},
|
|
652
|
-
annotations: {
|
|
653
|
-
title: "Package Info",
|
|
654
|
-
readOnlyHint: true,
|
|
655
|
-
destructiveHint: false,
|
|
656
|
-
idempotentHint: true,
|
|
657
|
-
openWorldHint: false
|
|
658
|
-
}
|
|
659
|
-
},
|
|
660
|
-
async (params) => {
|
|
661
|
-
try {
|
|
662
|
-
const result = await depsInfo(params.package, {
|
|
663
|
-
format: params.format,
|
|
664
|
-
cwd: params.cwd,
|
|
665
|
-
ctx: "mcp"
|
|
666
|
-
});
|
|
667
|
-
return { content: [{ type: "text", text: result }] };
|
|
668
|
-
} catch (error) {
|
|
669
|
-
const msg = error instanceof Error ? error.message : String(error);
|
|
670
|
-
const hint = recoveryHint("package_not_found", "mcp");
|
|
671
|
-
return {
|
|
672
|
-
content: [{ type: "text", text: `Erro ao executar deps info: ${msg}
|
|
673
|
-
${hint}` }],
|
|
674
|
-
isError: true
|
|
675
|
-
};
|
|
676
|
-
}
|
|
677
|
-
}
|
|
678
|
-
);
|
|
679
|
-
server2.registerTool(
|
|
680
|
-
"aitool_deps_api",
|
|
681
|
-
{
|
|
682
|
-
title: "Package API",
|
|
683
|
-
description: `API publica de um pacote instalado: funcoes, interfaces, tipos, enums exportados.
|
|
684
|
-
Extrai assinaturas dos arquivos .d.ts do node_modules local (diferencial vs ferramentas online).
|
|
685
|
-
|
|
686
|
-
Quando usar: aprender API de lib nova, ver tipos exportados, entender o que uma lib oferece.
|
|
687
|
-
NAO use para: ver metadados (use deps_info) ou buscar simbolo especifico (use deps_search).
|
|
688
|
-
|
|
689
|
-
Workflow: deps_info (overview) -> deps_api (API completa) -> deps_search (simbolo especifico)
|
|
690
|
-
Dica: Se a API estiver truncada, use deps_search com wildcards: "Button" (exato), "Button*" (prefixo), "*Button*" (cont\xE9m).
|
|
691
|
-
Dica: Para libs muito grandes (MUI, React), use --limit para controlar o output.`,
|
|
692
|
-
inputSchema: {
|
|
693
|
-
package: z.string().min(1).describe("Nome do pacote"),
|
|
694
|
-
limit: z.number().int().min(1).max(500).optional().describe("Limite de simbolos por tipo (default: 50)"),
|
|
695
|
-
offset: z.number().int().min(0).optional().describe("Offset para paginacao (default: 0)"),
|
|
696
|
-
entry: z.string().optional().describe("Sub-export especifico (ex: 'auth' para firebase/firestore)"),
|
|
697
|
-
kind: z.enum(["component", "hook", "function", "type", "interface", "enum", "const"]).optional().describe("Filtrar por tipo de simbolo (component|hook|function|type|interface|enum|const)"),
|
|
698
|
-
format: z.enum(["text", "json"]).default("text").describe("Formato de saida: text (legivel) ou json (estruturado)"),
|
|
699
|
-
cwd: z.string().optional().describe("Diretorio do projeto a analisar")
|
|
700
|
-
},
|
|
701
|
-
annotations: {
|
|
702
|
-
title: "Package API",
|
|
703
|
-
readOnlyHint: true,
|
|
704
|
-
destructiveHint: false,
|
|
705
|
-
idempotentHint: true,
|
|
706
|
-
openWorldHint: false
|
|
707
|
-
}
|
|
708
|
-
},
|
|
709
|
-
async (params) => {
|
|
710
|
-
try {
|
|
711
|
-
const result = await depsApi(params.package, {
|
|
712
|
-
format: params.format,
|
|
713
|
-
cwd: params.cwd,
|
|
714
|
-
limit: params.limit,
|
|
715
|
-
offset: params.offset,
|
|
716
|
-
entry: params.entry,
|
|
717
|
-
kind: params.kind,
|
|
718
|
-
ctx: "mcp"
|
|
719
|
-
});
|
|
720
|
-
return { content: [{ type: "text", text: result }] };
|
|
721
|
-
} catch (error) {
|
|
722
|
-
const msg = error instanceof Error ? error.message : String(error);
|
|
723
|
-
const hint = recoveryHint("package_not_found", "mcp");
|
|
724
|
-
return {
|
|
725
|
-
content: [{ type: "text", text: `Erro ao executar deps api: ${msg}
|
|
726
|
-
${hint}` }],
|
|
727
|
-
isError: true
|
|
728
|
-
};
|
|
729
|
-
}
|
|
730
|
-
}
|
|
731
|
-
);
|
|
732
|
-
server2.registerTool(
|
|
733
|
-
"aitool_deps_search",
|
|
734
|
-
{
|
|
735
|
-
title: "Search Package Symbol",
|
|
736
|
-
description: `Busca simbolo especifico na API de um pacote instalado.
|
|
737
|
-
Procura por nome em funcoes, tipos, interfaces, enums e constantes exportados.
|
|
738
|
-
|
|
739
|
-
Suporta wildcards: "Button" (exato), "Button*" (prefixo), "*Button" (sufixo), "*Button*" (cont\xE9m/substring).
|
|
740
|
-
|
|
741
|
-
Quando usar: verificar se uma lib exporta algo, encontrar um componente ou tipo especifico.
|
|
742
|
-
NAO use para: ver toda a API (use deps_api) ou metadados (use deps_info).
|
|
743
|
-
|
|
744
|
-
Dica: Sem wildcard = match exato. Use "*Button*" para buscar tudo que contem "Button".
|
|
745
|
-
Dica: Use deps_search para verificar imports antes de usar um simbolo.
|
|
746
|
-
|
|
747
|
-
Workflow: deps_info (overview) -> deps_api (API completa) -> deps_search (simbolo especifico)`,
|
|
748
|
-
inputSchema: {
|
|
749
|
-
package: z.string().min(1).describe("Nome do pacote"),
|
|
750
|
-
query: z.string().min(1).describe("Termo de busca (nome do simbolo)"),
|
|
751
|
-
kind: z.enum(["component", "hook", "function", "type", "interface", "enum", "const"]).optional().describe("Filtrar por tipo de simbolo (component|hook|function|type|interface|enum|const)"),
|
|
752
|
-
offset: z.number().int().min(0).optional().describe("Offset para paginacao (default: 0)"),
|
|
753
|
-
limit: z.number().int().min(1).max(200).optional().describe("Limite de resultados (default: 15)"),
|
|
754
|
-
format: z.enum(["text", "json"]).default("text").describe("Formato de saida: text (legivel) ou json (estruturado)"),
|
|
755
|
-
cwd: z.string().optional().describe("Diretorio do projeto a analisar")
|
|
756
|
-
},
|
|
757
|
-
annotations: {
|
|
758
|
-
title: "Search Package Symbol",
|
|
759
|
-
readOnlyHint: true,
|
|
760
|
-
destructiveHint: false,
|
|
761
|
-
idempotentHint: true,
|
|
762
|
-
openWorldHint: false
|
|
763
|
-
}
|
|
764
|
-
},
|
|
765
|
-
async (params) => {
|
|
766
|
-
try {
|
|
767
|
-
const result = await depsSearch(params.package, params.query, {
|
|
768
|
-
format: params.format,
|
|
769
|
-
cwd: params.cwd,
|
|
770
|
-
kind: params.kind,
|
|
771
|
-
offset: params.offset,
|
|
772
|
-
limit: params.limit,
|
|
773
|
-
ctx: "mcp"
|
|
774
|
-
});
|
|
775
|
-
return { content: [{ type: "text", text: result }] };
|
|
776
|
-
} catch (error) {
|
|
777
|
-
const msg = error instanceof Error ? error.message : String(error);
|
|
778
|
-
const hint = recoveryHint("package_not_found", "mcp");
|
|
779
|
-
return {
|
|
780
|
-
content: [{ type: "text", text: `Erro ao executar deps search: ${msg}
|
|
781
626
|
${hint}` }],
|
|
782
627
|
isError: true
|
|
783
628
|
};
|
package/package.json
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@justmpm/ai-tool",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "Ferramenta de análise de
|
|
3
|
+
"version": "4.0.0",
|
|
4
|
+
"description": "Ferramenta de análise de código para projetos TypeScript/JavaScript. Mapa do projeto, impacto de mudanças, código morto, Cloud Functions, busca de símbolos e áreas funcionais. Usa Skott + Knip + ts-morph internamente.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"dependency-analysis",
|
|
7
7
|
"impact-analysis",
|
|
8
8
|
"dead-code",
|
|
9
|
+
"code-analysis",
|
|
10
|
+
"symbol-search",
|
|
9
11
|
"typescript",
|
|
10
12
|
"javascript",
|
|
11
13
|
"skott",
|