@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.
@@ -201,18 +201,6 @@ var COMMAND_MAP = {
201
201
  changes_staged: {
202
202
  cli: "ai-tool changes --staged",
203
203
  mcp: "analyze__aitool_changes { target: 'staged' }"
204
- },
205
- deps_info: {
206
- cli: "ai-tool deps info <pacote>",
207
- mcp: "analyze__aitool_deps_info { package: '<pacote>' }"
208
- },
209
- deps_api: {
210
- cli: "ai-tool deps api <pacote>",
211
- mcp: "analyze__aitool_deps_api { package: '<pacote>' }"
212
- },
213
- deps_search: {
214
- cli: "ai-tool deps search <pacote> <termo>",
215
- mcp: "analyze__aitool_deps_search { package: '<pacote>', query: '<termo>' }"
216
204
  }
217
205
  };
218
206
  function hint(command, ctx, params) {
@@ -282,18 +270,6 @@ var NEXT_STEPS = {
282
270
  { command: "context", description: "ver assinaturas atuais de um arquivo modificado" },
283
271
  { command: "impact", description: "ver impacto das mudancas em outros arquivos" },
284
272
  { command: "suggest", description: "o que ler antes de editar um arquivo modificado" }
285
- ],
286
- deps_info: [
287
- { command: "deps_api", description: "ver API publica do pacote" },
288
- { command: "deps_search", description: "buscar simbolo especifico no pacote" }
289
- ],
290
- deps_api: [
291
- { command: "deps_search", description: "buscar simbolo especifico" },
292
- { command: "deps_info", description: "ver metadados do pacote" }
293
- ],
294
- deps_search: [
295
- { command: "deps_api", description: "ver toda a API publica" },
296
- { command: "deps_info", description: "ver metadados do pacote" }
297
273
  ]
298
274
  };
299
275
  function nextSteps(command, ctx) {
@@ -340,8 +316,16 @@ function recoveryHint(errorType, ctx, _extra) {
340
316
  return `
341
317
  \u{1F4A1} Nenhuma area configurada neste projeto.
342
318
  \u2192 ${hint("areas_init", ctx)} - gerar arquivo de configuracao
343
- \u2192 Depois edite .analyze/areas.config.json com as areas do projeto
344
319
  \u2192 ${hint("map", ctx)} - ver estrutura do projeto sem areas
320
+
321
+ Como configurar o areas.config.json:
322
+ - patterns: glob para pastas (ex: "app/dashboard/**", "hooks/usePets.*")
323
+ - keywords: substring no path, case-insensitive (ex: ["pet", "animal"])
324
+ - exclude: remove falsos positivos de uma area (ex: "components/pets/shared/**")
325
+ - descriptions: contexto manual para arquivos importantes (aparece no suggest, context, changes)
326
+ - settings.inferDescriptions: true para inferir descricoes automaticamente pelo nome do arquivo
327
+ - Um arquivo pode pertencer a multiplas areas
328
+ - Ideal: 5 a 15 areas (muitas = dificil de navegar)
345
329
  `;
346
330
  case "symbol_not_found":
347
331
  return `
@@ -351,12 +335,6 @@ function recoveryHint(errorType, ctx, _extra) {
351
335
  \u2192 ${hint("find", ctx)} - buscar com outro termo
352
336
  \u2192 ${hint("describe", ctx)} - buscar areas por descricao
353
337
  \u2192 ${hint("map", ctx)} - ver estrutura do projeto
354
- `;
355
- case "package_not_found":
356
- return `
357
- \u{1F4A1} Pacote nao encontrado no node_modules.
358
- \u2192 Verifique se o pacote esta instalado no projeto
359
- \u2192 ${hint("deps_info", ctx)} - use deps info para confirmar se esta instalado
360
338
  `;
361
339
  case "index_failed":
362
340
  return `
@@ -374,77 +352,6 @@ function recoveryHint(errorType, ctx, _extra) {
374
352
  }
375
353
  }
376
354
 
377
- // src/utils/semver.ts
378
- function parseVersion(version) {
379
- const trimmed = version.trim();
380
- const clean = trimmed.startsWith("v") ? trimmed.slice(1) : trimmed;
381
- const parts = clean.split(".");
382
- if (parts.length < 2) return null;
383
- const major = parseInt(parts[0], 10);
384
- if (isNaN(major)) return null;
385
- const minor = parseInt(parts[1], 10);
386
- if (isNaN(minor)) return null;
387
- const patch = parts.length >= 3 ? parseInt(parts[2], 10) : 0;
388
- if (isNaN(patch)) return null;
389
- return { major, minor, patch };
390
- }
391
- function compareSemver(a, b) {
392
- if (a.major !== b.major) return a.major < b.major ? -1 : 1;
393
- if (a.minor !== b.minor) return a.minor < b.minor ? -1 : 1;
394
- if (a.patch !== b.patch) return a.patch < b.patch ? -1 : 1;
395
- return 0;
396
- }
397
- function satisfiesComparator(installed, comparator) {
398
- const trimmed = comparator.trim();
399
- if (trimmed.startsWith("^")) {
400
- const target = parseVersion(trimmed.slice(1));
401
- if (!target) return true;
402
- return installed.major === target.major && compareSemver(installed, target) >= 0;
403
- }
404
- if (trimmed.startsWith("~")) {
405
- const target = parseVersion(trimmed.slice(1));
406
- if (!target) return true;
407
- return installed.major === target.major && installed.minor === target.minor && compareSemver(installed, target) >= 0;
408
- }
409
- if (trimmed.startsWith(">=")) {
410
- const target = parseVersion(trimmed.slice(2));
411
- if (!target) return true;
412
- return compareSemver(installed, target) >= 0;
413
- }
414
- if (trimmed.startsWith("<=")) {
415
- const target = parseVersion(trimmed.slice(2));
416
- if (!target) return true;
417
- return compareSemver(installed, target) <= 0;
418
- }
419
- if (trimmed.startsWith(">") && !trimmed.startsWith(">=")) {
420
- const target = parseVersion(trimmed.slice(1));
421
- if (!target) return true;
422
- return compareSemver(installed, target) > 0;
423
- }
424
- if (trimmed.startsWith("<") && !trimmed.startsWith("<=")) {
425
- const target = parseVersion(trimmed.slice(1));
426
- if (!target) return true;
427
- return compareSemver(installed, target) < 0;
428
- }
429
- const exact = parseVersion(trimmed);
430
- if (!exact) return true;
431
- return compareSemver(installed, exact) === 0;
432
- }
433
- function satisfiesSemver(installed, declared) {
434
- const installedVersion = parseVersion(installed);
435
- if (!installedVersion) return true;
436
- const orParts = declared.split("||");
437
- for (const orPart of orParts) {
438
- const comparators = orPart.trim().split(/\s+/).filter((c) => c.length > 0);
439
- if (comparators.length === 0) continue;
440
- const allSatisfy = comparators.every(
441
- (comp) => satisfiesComparator(installedVersion, comp)
442
- );
443
- if (allSatisfy) return true;
444
- }
445
- return false;
446
- }
447
-
448
355
  // src/utils/similarity.ts
449
356
  function levenshteinDistance(a, b) {
450
357
  const matrix = [];
@@ -626,6 +533,8 @@ function formatMapSummary(result, areasInfo, ctx = "cli") {
626
533
  out += ` \u2192 ${hint("areas_missing", ctx)} para ver quais arquivos estao sem area
627
534
  `;
628
535
  out += ` \u2192 ${hint("areas_init", ctx)} para criar/editar areas.config
536
+ `;
537
+ out += ` Boas praticas: patterns (glob exato) para pastas, keywords (case-insensitive) para arquivos espalhados, exclude para falsos positivos
629
538
 
630
539
  `;
631
540
  }
@@ -1895,65 +1804,6 @@ AFFECTED AREAS:
1895
1804
  const semanticFiles = result.files.filter((f) => f.changes.length > 0 && !f.newFile);
1896
1805
  const newFiles = result.files.filter((f) => f.newFile);
1897
1806
  const otherFiles = result.files.filter((f) => f.changes.length === 0 && !f.newFile);
1898
- const COMPACT_THRESHOLD = 10;
1899
- const filesExceedThreshold = semanticFiles.length + newFiles.length > COMPACT_THRESHOLD;
1900
- if (filesExceedThreshold) {
1901
- out += `
1902
- COMPACT MODE: Too many files. Use --file=<path> for details.
1903
-
1904
- `;
1905
- const modifiedCompact = result.files.filter((f) => !f.newFile);
1906
- const renamedCompact = modifiedCompact.filter((f) => f.renamed);
1907
- const otherModifiedCompact = modifiedCompact.filter((f) => !f.renamed);
1908
- if (otherModifiedCompact.length > 0) {
1909
- out += `Modified files:
1910
- `;
1911
- for (const file of otherModifiedCompact) {
1912
- const changeCount = file.changes.length;
1913
- out += ` ${file.path} (+${file.stats.added} -${file.stats.removed})`;
1914
- if (changeCount > 0) {
1915
- out += ` - ${changeCount} changes`;
1916
- } else {
1917
- out += ` - (no semantic changes)`;
1918
- }
1919
- out += `
1920
- `;
1921
- }
1922
- }
1923
- if (renamedCompact.length > 0) {
1924
- out += `
1925
- Renamed files:
1926
- `;
1927
- for (const file of renamedCompact) {
1928
- out += ` ${file.renamedFrom} -> ${file.path} (+${file.stats.added} -${file.stats.removed})`;
1929
- const changeCount = file.changes.length;
1930
- if (changeCount > 0) {
1931
- out += ` - ${changeCount} changes`;
1932
- }
1933
- out += `
1934
- `;
1935
- }
1936
- }
1937
- if (newFiles.length > 0) {
1938
- out += `
1939
- New files (untracked):
1940
- `;
1941
- for (const file of newFiles) {
1942
- const changeCount = file.changes.length;
1943
- out += ` ${file.path} (+${file.stats.added} new)`;
1944
- if (changeCount > 0) {
1945
- out += ` - ${changeCount} symbols`;
1946
- }
1947
- out += `
1948
- `;
1949
- }
1950
- }
1951
- out += `
1952
- Use: ${hint("changes", ctx)} --file=<arquivo>
1953
- `;
1954
- out += nextSteps("changes", ctx);
1955
- return out;
1956
- }
1957
1807
  for (const file of semanticFiles) {
1958
1808
  out += `
1959
1809
  --- ${file.path} (+${file.stats.added} -${file.stats.removed}) ---
@@ -2147,410 +1997,6 @@ function formatUsageExamples(examples, indent = 2) {
2147
1997
  }
2148
1998
  return out;
2149
1999
  }
2150
- function formatDepsInfoText(result, ctx = "cli") {
2151
- let out = "";
2152
- const info = result.info;
2153
- const name = info.name || result.package;
2154
- out += `${name} v${info.version}`;
2155
- out += `
2156
- `;
2157
- if (result.declaredVersion) {
2158
- if (satisfiesSemver(info.version, result.declaredVersion)) {
2159
- out += ` Status: OK
2160
- `;
2161
- } else {
2162
- out += ` Status: desatualizada (declarada: ${result.declaredVersion})
2163
- `;
2164
- }
2165
- }
2166
- if (info.description) {
2167
- out += ` Descricao: ${info.description}
2168
- `;
2169
- }
2170
- if (info.hasTypes) {
2171
- if (info.typesSource === "@types" && info.typesPackage) {
2172
- out += ` Tipos: ${info.typesPackage} (pacote separado)
2173
- `;
2174
- } else if (info.types) {
2175
- out += ` Tipos: ${info.types}
2176
- `;
2177
- } else if (info.typings) {
2178
- out += ` Tipos: ${info.typings}
2179
- `;
2180
- } else {
2181
- out += ` Tipos: embutidos (via exports)
2182
- `;
2183
- }
2184
- }
2185
- const mainEntries = result.entryPoints.filter(
2186
- (ep) => ep.type === "main" || ep.type === "types" || ep.type === "module"
2187
- );
2188
- const otherCount = result.entryPoints.length - mainEntries.length;
2189
- out += ` Entry points: (${result.entryPoints.length})
2190
- `;
2191
- const topLevel = mainEntries.filter((ep) => {
2192
- const conditions = ep.condition.split(", ");
2193
- return conditions.every((c) => !c.startsWith("./"));
2194
- });
2195
- const subExports = mainEntries.filter((ep) => {
2196
- const conditions = ep.condition.split(", ");
2197
- return conditions.some((c) => c.startsWith("./"));
2198
- });
2199
- for (const ep of topLevel) {
2200
- const fileName = ep.path.split(/[\\/]/).pop() || ep.path;
2201
- const conditions = ep.condition.split(", ");
2202
- if (conditions.length > 1) {
2203
- out += ` ${ep.type}: ${fileName} [${conditions.length} conditions]
2204
- `;
2205
- } else {
2206
- out += ` ${ep.type}: ${fileName}
2207
- `;
2208
- }
2209
- }
2210
- if (subExports.length > 0) {
2211
- const grouped = /* @__PURE__ */ new Map();
2212
- for (const ep of subExports) {
2213
- const conditions = ep.condition.split(", ");
2214
- const subExportCondition = conditions.find((c) => c.startsWith("./"));
2215
- if (!subExportCondition) continue;
2216
- const exportKeyMatch = subExportCondition.match(/^(\.\/[^/]+)/);
2217
- const exportKey = exportKeyMatch ? exportKeyMatch[1] : subExportCondition;
2218
- const existing = grouped.get(exportKey);
2219
- if (existing) {
2220
- existing.push({ condition: subExportCondition, path: ep.path, type: ep.type });
2221
- } else {
2222
- grouped.set(exportKey, [{ condition: subExportCondition, path: ep.path, type: ep.type }]);
2223
- }
2224
- }
2225
- out += ` Sub-exports (${grouped.size}):
2226
- `;
2227
- for (const [exportKey, entries] of grouped) {
2228
- const moduleName = exportKey.replace(/^\.\//, "");
2229
- const normalizedPath = entries[0].path.replace(/\\/g, "/");
2230
- const pkgMatch = normalizedPath.match(/node_modules\/[^/]+\/(.+)/);
2231
- const relativePath = pkgMatch ? pkgMatch[1] : normalizedPath.split(/[\\/]/).pop() || entries[0].path;
2232
- if (entries.length === 1) {
2233
- out += ` ${moduleName}: ${relativePath}
2234
- `;
2235
- } else {
2236
- const variantNames = entries.map((e) => {
2237
- const cond = e.condition.split(", ").find((c) => c.startsWith("./"));
2238
- return cond?.replace(/^\.\/[^/]+\//, "") || "";
2239
- }).filter(Boolean);
2240
- out += ` ${moduleName}: ${relativePath} [${variantNames.join(", ")}]
2241
- `;
2242
- }
2243
- }
2244
- }
2245
- if (otherCount > 0) {
2246
- out += ` + ${otherCount} condicional(is) via exports
2247
- `;
2248
- }
2249
- if (info.repository) {
2250
- out += ` Repository: ${info.repository}
2251
- `;
2252
- }
2253
- if (info.homepage) {
2254
- out += ` Homepage: ${info.homepage}
2255
- `;
2256
- }
2257
- if (info.license) {
2258
- out += ` License: ${info.license}
2259
- `;
2260
- }
2261
- const peerDeps = Object.entries(info.peerDependencies);
2262
- if (peerDeps.length > 0) {
2263
- out += `
2264
- Peer dependencies (${peerDeps.length}):
2265
- `;
2266
- for (const [depName, depVer] of peerDeps.slice(0, 5)) {
2267
- out += ` ${depName}: ${depVer}
2268
- `;
2269
- }
2270
- if (peerDeps.length > 5) {
2271
- out += ` + ${peerDeps.length - 5} outras
2272
- `;
2273
- }
2274
- }
2275
- const directDeps = Object.entries(info.dependencies);
2276
- if (directDeps.length > 0) {
2277
- const depCount = directDeps.length;
2278
- out += ` Dependencias diretas: ${depCount}`;
2279
- if (depCount > 0) {
2280
- out += ` (top 5):
2281
- `;
2282
- for (const [depName, depVer] of directDeps.slice(0, 5)) {
2283
- out += ` ${depName}: ${depVer}
2284
- `;
2285
- }
2286
- if (depCount > 5) {
2287
- out += ` + ${depCount - 5} outras
2288
- `;
2289
- }
2290
- } else {
2291
- out += `
2292
- `;
2293
- }
2294
- }
2295
- out += nextSteps("deps_info", ctx);
2296
- return out;
2297
- }
2298
- function formatDepsApiText(result, ctx = "cli") {
2299
- let out = "";
2300
- const typeFileLabel = result.typeFilesSummary ? result.typeFilesSummary : result.typeFiles.length === 1 ? "1 type file" : `${result.typeFiles.length} type files`;
2301
- if (result.typesSource === "@types") {
2302
- out += `${result.package} - API Publica (via ${result.typesPackage})
2303
-
2304
- `;
2305
- } else if (result.typesSource === "js-fallback" || result.jsFallback) {
2306
- out += `${result.package} - API Publica (tipos aproximados de JS)
2307
-
2308
- `;
2309
- } else if (result.typesSource === "builtin") {
2310
- out += `${result.package} - API Publica (${typeFileLabel} - tipos embutidos)
2311
-
2312
- `;
2313
- } else {
2314
- out += `${result.package} - API Publica (${typeFileLabel})
2315
-
2316
- `;
2317
- }
2318
- if (result.typeFilesPreview && result.typeFilesPreview.length > 0) {
2319
- out += `TYPE FILES (top ${result.typeFilesPreview.length})
2320
- `;
2321
- for (const tf of result.typeFilesPreview) {
2322
- out += ` ${tf}
2323
- `;
2324
- }
2325
- out += `
2326
- `;
2327
- }
2328
- const components = result.functions.filter((f) => f.kind === "component");
2329
- const hooks = result.functions.filter((f) => f.kind === "hook");
2330
- const plainFunctions = result.functions.filter((f) => f.kind !== "component" && f.kind !== "hook");
2331
- if (components.length > 0) {
2332
- out += `COMPONENTS (${components.length})
2333
- `;
2334
- for (const fn of components) {
2335
- const params = fn.params.map((p) => `${p.name}: ${p.type}`).join(", ");
2336
- out += ` ${fn.name}(${params}): ${fn.returnType}
2337
- `;
2338
- }
2339
- out += `
2340
- `;
2341
- }
2342
- if (hooks.length > 0) {
2343
- out += `HOOKS (${hooks.length})
2344
- `;
2345
- for (const fn of hooks) {
2346
- const asyncLabel = fn.isAsync ? "async " : "";
2347
- const params = fn.params.map((p) => `${p.name}: ${p.type}`).join(", ");
2348
- out += ` ${asyncLabel}${fn.name}(${params}): ${fn.returnType}
2349
- `;
2350
- }
2351
- out += `
2352
- `;
2353
- }
2354
- if (plainFunctions.length > 0) {
2355
- out += `FUNCTIONS (${plainFunctions.length})
2356
- `;
2357
- for (const fn of plainFunctions) {
2358
- const asyncLabel = fn.isAsync ? "async " : "";
2359
- const params = fn.params.map((p) => `${p.name}: ${p.type}`).join(", ");
2360
- out += ` ${asyncLabel}${fn.name}(${params}): ${fn.returnType}
2361
- `;
2362
- }
2363
- out += `
2364
- `;
2365
- }
2366
- const interfaces = result.types.filter((t) => t.kind === "interface");
2367
- const typeAliases = result.types.filter((t) => t.kind === "type");
2368
- const enums = result.types.filter((t) => t.kind === "enum");
2369
- if (interfaces.length > 0) {
2370
- out += `INTERFACES (${interfaces.length})
2371
- `;
2372
- for (const t of interfaces) {
2373
- const def = truncateText(t.definition, 100);
2374
- out += ` ${t.name}
2375
- `;
2376
- out += ` ${def}
2377
- `;
2378
- }
2379
- out += `
2380
- `;
2381
- }
2382
- if (typeAliases.length > 0) {
2383
- out += `TYPE ALIASES (${typeAliases.length})
2384
- `;
2385
- for (const t of typeAliases) {
2386
- const def = truncateText(t.definition, 100);
2387
- out += ` ${def}
2388
- `;
2389
- }
2390
- out += `
2391
- `;
2392
- }
2393
- if (enums.length > 0) {
2394
- out += `ENUMS (${enums.length})
2395
- `;
2396
- for (const t of enums) {
2397
- const def = truncateText(t.definition, 100);
2398
- out += ` ${def}
2399
- `;
2400
- }
2401
- out += `
2402
- `;
2403
- }
2404
- if (result.constants && result.constants.length > 0) {
2405
- out += `CONSTANTS (${result.constants.length})
2406
- `;
2407
- for (const c of result.constants) {
2408
- out += ` ${c.name}: ${c.type}
2409
- `;
2410
- }
2411
- out += `
2412
- `;
2413
- }
2414
- if (result.truncated.functions || result.truncated.types) {
2415
- if (result.truncated.functions) {
2416
- const total = result.truncated.totalFunctions ?? 50;
2417
- out += `[truncated: functions ${result.functions.length}/${total}]
2418
- `;
2419
- }
2420
- if (result.truncated.types) {
2421
- const total = result.truncated.totalTypes ?? 50;
2422
- out += `[truncated: types ${result.types.length}/${total}]
2423
- `;
2424
- }
2425
- out += `Use ${hint("deps_search", ctx, { "<pacote>": result.package, "<termo>": "*Symbol*" })} para buscar simbolos especificos
2426
- `;
2427
- }
2428
- if (result.availableKindsWhenFilteredEmpty && result.availableKindsWhenFilteredEmpty.length > 0) {
2429
- const kinds = result.availableKindsWhenFilteredEmpty.map((k) => `${k.kind} (${k.count})`).join(", ");
2430
- out += `
2431
- Filtro --kind nao encontrou simbolos, mas ha outros tipos disponiveis:
2432
- `;
2433
- out += ` ${kinds}
2434
- `;
2435
- out += ` Use ${hint("deps_api", ctx, { "<pacote>": result.package })} sem filtro --kind para ver tudo
2436
- `;
2437
- }
2438
- out += nextSteps("deps_api", ctx);
2439
- return out;
2440
- }
2441
- function formatDepsSearchText(result, ctx = "cli") {
2442
- let out = "";
2443
- if (result.typesSource === "@types") {
2444
- out += `${result.package} - Busca: "${result.query}" (via ${result.typesPackage})
2445
-
2446
- `;
2447
- } else if (result.typesSource === "js-fallback" || result.jsFallback) {
2448
- out += `${result.package} - Busca: "${result.query}" (tipos aproximados)
2449
-
2450
- `;
2451
- } else if (result.typesSource === "builtin") {
2452
- out += `${result.package} - Busca: "${result.query}" (tipos embutidos)
2453
-
2454
- `;
2455
- } else {
2456
- out += `${result.package} - Busca: "${result.query}"
2457
-
2458
- `;
2459
- }
2460
- if (result.matches.length === 0) {
2461
- out += `Nenhum simbolo encontrado para "${result.query}".
2462
- `;
2463
- if (result.availableKindsWhenEmpty && result.availableKindsWhenEmpty.length > 0) {
2464
- const kinds = result.availableKindsWhenEmpty.map((k) => `"${k}"`).join(", ");
2465
- out += `
2466
- Simbolos encontrados, mas como tipo diferente:
2467
- `;
2468
- out += ` Kinds disponiveis: ${kinds}
2469
- `;
2470
- out += ` Tente: ${hint("deps_search", ctx, { "<pacote>": result.package, "<termo>": result.query })} sem filtro --kind
2471
- `;
2472
- }
2473
- if (result.typesSource === void 0 && !result.jsFallback) {
2474
- out += `
2475
- Pacote "${result.package}" nao possui TypeScript declarations.
2476
- `;
2477
- out += ` Instale com: npm install -D @types/${result.package}
2478
- `;
2479
- }
2480
- out += `
2481
- Dicas:
2482
- `;
2483
- out += ` -> Verifique a ortografia
2484
- `;
2485
- out += ` -> Tente buscar parte do nome (ex: "Btn" em vez de "Button")
2486
- `;
2487
- out += ` -> ${hint("deps_api", ctx, { "<pacote>": result.package })} - ver toda a API
2488
- `;
2489
- return out;
2490
- }
2491
- for (let i = 0; i < result.matches.length; i++) {
2492
- const match = result.matches[i];
2493
- out += `${i + 1}. ${match.name} (${match.kind})`;
2494
- if (match.fromConcept) {
2495
- out += ` [conceito: "${match.fromConcept}"]`;
2496
- }
2497
- out += `
2498
- `;
2499
- out += ` ${match.file}
2500
- `;
2501
- const sig = truncateText(match.signature, 100);
2502
- out += ` ${sig}
2503
- `;
2504
- out += `
2505
- `;
2506
- }
2507
- if (result.summary.byKind && result.summary.byKind.length > 1) {
2508
- out += `POR KIND:
2509
- `;
2510
- for (const k of result.summary.byKind) {
2511
- if (k.total > 0) {
2512
- const truncInfo = k.shown < k.total ? ` (${k.shown}/${k.total})` : "";
2513
- out += ` ${k.kind}: ${k.total}${truncInfo}
2514
- `;
2515
- }
2516
- }
2517
- }
2518
- if (result.summary.byFile && result.summary.byFile.length > 1) {
2519
- out += `POR ARQUIVO:
2520
- `;
2521
- for (const f of result.summary.byFile) {
2522
- if (f.count > 1) {
2523
- out += ` ${f.file}: ${f.count} matches
2524
- `;
2525
- }
2526
- }
2527
- }
2528
- const shown = result.summary.shown;
2529
- const total = result.summary.total;
2530
- const hidden = result.summary.hidden;
2531
- const pluralTotal = total !== 1 ? "s" : "";
2532
- const pluralFiles = result.summary.files !== 1 ? "s" : "";
2533
- if (hidden > 0) {
2534
- out += `${shown} de ${total} resultado${pluralTotal} (${hidden} hidden)
2535
- `;
2536
- out += ` em ${result.summary.files} arquivo${pluralFiles}
2537
- `;
2538
- } else {
2539
- out += `${total} resultado${pluralTotal} em ${result.summary.files} arquivo${pluralFiles}
2540
- `;
2541
- }
2542
- if (total > 50) {
2543
- out += `
2544
- Muitos resultados encontrados. Refine a busca com termos mais especificos.
2545
- `;
2546
- }
2547
- out += nextSteps("deps_search", ctx);
2548
- return out;
2549
- }
2550
- function truncateText(text, maxLen) {
2551
- if (text.length <= maxLen) return text;
2552
- return text.substring(0, maxLen - 3) + "...";
2553
- }
2554
2000
 
2555
2001
  // src/cache/index.ts
2556
2002
  import {
@@ -7005,14 +6451,20 @@ Ou edite manualmente o arquivo existente.
7005
6451
  ai-tool area auth # Ver arquivos de uma \xE1rea
7006
6452
  ai-tool map # Ver resumo do projeto
7007
6453
 
7008
- \u{1F4A1} Dicas:
6454
+ \u{1F4A1} Dicas:
7009
6455
 
7010
- \u2022 Use patterns para pastas: "app/dashboard/**"
7011
- \u2022 Use keywords para arquivos espalhados: ["auth", "login"]
7012
- \u2022 Um arquivo pode pertencer a m\xFAltiplas \xE1reas
7013
- \u2022 Use "exclude" para remover arquivos espec\xEDficos de uma \xE1rea
6456
+ \u2022 patterns: glob para pastas (ex: "app/dashboard/**", "hooks/usePets.*")
6457
+ \u2022 keywords: substring no path inteiro, case-insensitive (ex: ["pet", "animal"])
6458
+ \u2022 Um arquivo pode pertencer a m\xFAltiplas \xE1reas
6459
+ \u2022 exclude: remove falsos positivos de uma \xE1rea (glob patterns)
6460
+ \u2022 descriptions (campo raiz): contexto manual para arquivos importantes
6461
+ Aparece nos comandos suggest, context e changes
6462
+ Ex: "src/hooks/useAuth.ts": "Hook principal de autentica\xE7\xE3o"
6463
+ \u2022 settings.inferDescriptions: true j\xE1 infere descri\xE7\xF5es automaticamente
6464
+ pelo nome do arquivo (ex: useAuth.ts \u2192 "Hook de auth", petService.ts \u2192 "Service de pet")
6465
+ Ativado por padr\xE3o no template gerado
7014
6466
 
7015
- \u{1F4D6} Exemplo completo:
6467
+ \u{1F4D6} Exemplo completo:
7016
6468
 
7017
6469
  {
7018
6470
  "areas": {
@@ -8771,13 +8223,7 @@ export {
8771
8223
  findSimilar,
8772
8224
  findBestMatch,
8773
8225
  extractFileName,
8774
- formatDepsInfoText,
8775
- formatDepsApiText,
8776
- formatDepsSearchText,
8777
- logger,
8778
8226
  getWorkspaceFiles,
8779
- simplifyType,
8780
- expandMuiOverrideType,
8781
8227
  getProjectIndexArtifact,
8782
8228
  isFirebaseProject,
8783
8229
  hasFirebaseFunctions,
@@ -8810,10 +8256,6 @@ export {
8810
8256
  formatInvalidCommand,
8811
8257
  impact,
8812
8258
  suggest,
8813
- addSourceFile,
8814
- extractFunctions,
8815
- extractTypes,
8816
- extractExports,
8817
8259
  context,
8818
8260
  areaContext,
8819
8261
  areas,