@justmpm/ai-tool 1.0.0 → 1.0.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.
@@ -297,6 +297,29 @@ function recoveryHint(errorType, ctx, _extra) {
297
297
  \u2192 ${hint("map", ctx)} - ver estrutura do projeto
298
298
  \u2192 ${hint("find", ctx)} - buscar simbolos no codigo
299
299
  \u2192 ${hint("areas", ctx)} - listar areas funcionais
300
+ `;
301
+ case "no_areas_configured":
302
+ return `
303
+ \u{1F4A1} Nenhuma area configurada neste projeto.
304
+ \u2192 ${hint("areas_init", ctx)} - gerar arquivo de configuracao
305
+ \u2192 Depois edite .analyze/areas.config.json com as areas do projeto
306
+ \u2192 ${hint("map", ctx)} - ver estrutura do projeto sem areas
307
+ `;
308
+ case "symbol_not_found":
309
+ return `
310
+ \u{1F4A1} Dicas:
311
+ \u2192 Verifique a ortografia do simbolo
312
+ \u2192 Tente buscar parte do nome
313
+ \u2192 ${hint("find", ctx)} - buscar com outro termo
314
+ \u2192 ${hint("describe", ctx)} - buscar areas por descricao
315
+ \u2192 ${hint("map", ctx)} - ver estrutura do projeto
316
+ `;
317
+ case "index_failed":
318
+ return `
319
+ \u{1F4A1} Falha ao indexar o projeto:
320
+ \u2192 Verifique se tsconfig.json existe e esta valido
321
+ \u2192 Verifique se o projeto tem arquivos .ts ou .tsx
322
+ \u2192 ${hint("map", ctx)} - tente ver a estrutura basica primeiro
300
323
  `;
301
324
  case "generic":
302
325
  return `
@@ -373,6 +396,10 @@ function extractFileName(filePath) {
373
396
  // src/formatters/text.ts
374
397
  function formatMapSummary(result, areasInfo, ctx = "cli") {
375
398
  let out = "";
399
+ if (result.framework) {
400
+ out += `\u{1F3D7}\uFE0F Framework: ${result.framework}
401
+ `;
402
+ }
376
403
  out += `\u{1F4CA} ${result.summary.totalFiles} arquivos | ${result.summary.totalFolders} pastas
377
404
  `;
378
405
  const catOrder = [
@@ -399,11 +426,23 @@ function formatMapSummary(result, areasInfo, ctx = "cli") {
399
426
  }
400
427
  out += ` ${catParts.join(", ")}
401
428
  `;
402
- const topFolders = result.folders.sort((a, b) => b.fileCount - a.fileCount).slice(0, 5);
403
- if (topFolders.length > 0) {
404
- const folderParts = topFolders.map((f) => `${f.path}/ (${f.fileCount})`);
405
- out += `\u{1F4C1} ${folderParts.join(", ")}
429
+ const SMALL_PROJECT_THRESHOLD = 25;
430
+ if (result.summary.totalFiles <= SMALL_PROJECT_THRESHOLD && result.files.length > 0) {
431
+ out += `
432
+ \u{1F4C1} Arquivos:
406
433
  `;
434
+ for (const file of result.files) {
435
+ const icon = categoryIcons[file.category];
436
+ out += ` ${icon} ${file.path}
437
+ `;
438
+ }
439
+ } else {
440
+ const topFolders = result.folders.sort((a, b) => b.fileCount - a.fileCount).slice(0, 5);
441
+ if (topFolders.length > 0) {
442
+ const folderParts = topFolders.map((f) => `${f.path}/ (${f.fileCount})`);
443
+ out += `\u{1F4C1} ${folderParts.join(", ")}
444
+ `;
445
+ }
407
446
  }
408
447
  if (areasInfo && areasInfo.total > 0) {
409
448
  out += `
@@ -1020,7 +1059,36 @@ function formatContextText(result, ctx = "cli") {
1020
1059
  out += ` Constants: ${result.constants.length}
1021
1060
  `;
1022
1061
  }
1023
- out += nextSteps("context", ctx);
1062
+ out += `
1063
+ \u{1F4D6} Proximos passos:
1064
+ `;
1065
+ const exportedFns = result.functions.filter((f) => f.isExported);
1066
+ const exportedTypes = result.types.filter((t) => t.isExported);
1067
+ if (exportedFns.length > 0) {
1068
+ const mainExport = exportedFns[0].name;
1069
+ out += ` \u2192 ${hint("find", ctx, { "<termo>": mainExport })} - ver onde ${mainExport} e usado
1070
+ `;
1071
+ }
1072
+ const isHook = result.category === "hook" || result.functions.some((f) => f.name.startsWith("use"));
1073
+ if (isHook) {
1074
+ out += ` \u2192 ${hint("impact", ctx, { "<arquivo>": result.file })} - ver quem usa este hook
1075
+ `;
1076
+ }
1077
+ if (result.category === "service") {
1078
+ out += ` \u2192 ${hint("impact", ctx, { "<arquivo>": result.file })} - ver quem usa este service
1079
+ `;
1080
+ }
1081
+ if (exportedTypes.length > 0) {
1082
+ const mainType = exportedTypes[0].name;
1083
+ out += ` \u2192 ${hint("find", ctx, { "<termo>": mainType })} - ver onde ${mainType} e usado
1084
+ `;
1085
+ }
1086
+ if (!isHook && result.category !== "service") {
1087
+ out += ` \u2192 ${hint("impact", ctx, { "<arquivo>": result.file })} - ver quem sera afetado por mudancas
1088
+ `;
1089
+ }
1090
+ out += ` \u2192 ${hint("suggest", ctx, { "<arquivo>": result.file })} - o que ler antes de editar
1091
+ `;
1024
1092
  return out;
1025
1093
  }
1026
1094
  function formatAreasText(result, ctx = "cli") {
@@ -1995,10 +2063,37 @@ function formatOutput(result, format, textFormatter, cacheMarker) {
1995
2063
  }
1996
2064
 
1997
2065
  // src/commands/map.ts
2066
+ import { existsSync as existsSync4 } from "fs";
2067
+ import { join as join4 } from "path";
2068
+ function detectFramework(cwd) {
2069
+ if (existsSync4(join4(cwd, "next.config.js")) || existsSync4(join4(cwd, "next.config.ts")) || existsSync4(join4(cwd, "next.config.mjs"))) {
2070
+ return "Next.js";
2071
+ }
2072
+ if (existsSync4(join4(cwd, "vite.config.ts")) || existsSync4(join4(cwd, "vite.config.js"))) {
2073
+ return "Vite";
2074
+ }
2075
+ if (existsSync4(join4(cwd, "remix.config.js")) || existsSync4(join4(cwd, "remix.config.ts"))) {
2076
+ return "Remix";
2077
+ }
2078
+ if (existsSync4(join4(cwd, "astro.config.mjs")) || existsSync4(join4(cwd, "astro.config.ts"))) {
2079
+ return "Astro";
2080
+ }
2081
+ if (existsSync4(join4(cwd, "nuxt.config.ts")) || existsSync4(join4(cwd, "nuxt.config.js"))) {
2082
+ return "Nuxt";
2083
+ }
2084
+ if (existsSync4(join4(cwd, "svelte.config.js")) || existsSync4(join4(cwd, "svelte.config.ts"))) {
2085
+ return "SvelteKit";
2086
+ }
2087
+ if (existsSync4(join4(cwd, ".firebaserc")) || existsSync4(join4(cwd, "firebase.json"))) {
2088
+ return "Firebase";
2089
+ }
2090
+ return void 0;
2091
+ }
1998
2092
  async function map(options = {}) {
1999
2093
  const { cwd, format } = parseCommandOptions(options);
2000
2094
  const useCache = options.cache !== false;
2001
2095
  const full = options.full ?? false;
2096
+ const ctx = options.ctx || "cli";
2002
2097
  if (useCache && isCacheValid(cwd)) {
2003
2098
  const cached = getCachedMapResult(cwd);
2004
2099
  if (cached) {
@@ -2007,10 +2102,10 @@ async function map(options = {}) {
2007
2102
  return JSON.stringify(result, null, 2);
2008
2103
  }
2009
2104
  if (full) {
2010
- return formatMapText(result) + "\n\n\u{1F4E6} (resultado do cache)";
2105
+ return formatMapText(result, ctx) + "\n\n\u{1F4E6} (resultado do cache)";
2011
2106
  }
2012
2107
  const areasInfo = detectAreasInfo(cwd, result.files.map((f) => f.path));
2013
- return formatMapSummary(result, areasInfo) + "\n\u{1F4E6} (cache)";
2108
+ return formatMapSummary(result, areasInfo, ctx) + "\n\u{1F4E6} (cache)";
2014
2109
  }
2015
2110
  }
2016
2111
  try {
@@ -2064,10 +2159,12 @@ async function map(options = {}) {
2064
2159
  categories[file.category] = (categories[file.category] || 0) + 1;
2065
2160
  }
2066
2161
  const circular = findCircularDependencies();
2162
+ const framework = detectFramework(cwd);
2067
2163
  const result = {
2068
2164
  version: "1.0.0",
2069
2165
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2070
2166
  cwd,
2167
+ framework,
2071
2168
  summary: {
2072
2169
  totalFiles: files.length,
2073
2170
  totalFolders: folderMap.size,
@@ -2085,10 +2182,10 @@ async function map(options = {}) {
2085
2182
  return JSON.stringify(result, null, 2);
2086
2183
  }
2087
2184
  if (full) {
2088
- return formatMapText(result);
2185
+ return formatMapText(result, ctx);
2089
2186
  }
2090
2187
  const areasInfo = detectAreasInfo(cwd, files.map((f) => f.path));
2091
- return formatMapSummary(result, areasInfo);
2188
+ return formatMapSummary(result, areasInfo, ctx);
2092
2189
  } catch (error) {
2093
2190
  const message = error instanceof Error ? error.message : String(error);
2094
2191
  throw new Error(`Erro ao executar map: ${message}`);
@@ -2126,8 +2223,8 @@ function detectAreasInfo(cwd, filePaths) {
2126
2223
 
2127
2224
  // src/commands/dead.ts
2128
2225
  import { execSync } from "child_process";
2129
- import { writeFileSync as writeFileSync3, unlinkSync, existsSync as existsSync4 } from "fs";
2130
- import { join as join4 } from "path";
2226
+ import { writeFileSync as writeFileSync3, unlinkSync, existsSync as existsSync5 } from "fs";
2227
+ import { join as join5 } from "path";
2131
2228
  function generateKnipConfig(cwd) {
2132
2229
  const ignorePatterns = getIgnorePatterns(cwd);
2133
2230
  if (ignorePatterns.length === 0) {
@@ -2137,7 +2234,7 @@ function generateKnipConfig(cwd) {
2137
2234
  $schema: "https://unpkg.com/knip@5/schema.json",
2138
2235
  ignore: ignorePatterns
2139
2236
  };
2140
- const configPath = join4(cwd, ".knip.ai-tool.json");
2237
+ const configPath = join5(cwd, ".knip.ai-tool.json");
2141
2238
  writeFileSync3(configPath, JSON.stringify(knipConfig, null, 2), "utf-8");
2142
2239
  return configPath;
2143
2240
  }
@@ -2175,7 +2272,7 @@ async function dead(options = {}) {
2175
2272
  knipOutput = {};
2176
2273
  }
2177
2274
  } finally {
2178
- if (knipConfigPath && existsSync4(knipConfigPath)) {
2275
+ if (knipConfigPath && existsSync5(knipConfigPath)) {
2179
2276
  try {
2180
2277
  unlinkSync(knipConfigPath);
2181
2278
  } catch {
@@ -2258,29 +2355,33 @@ ${output}`;
2258
2355
  import skott2 from "skott";
2259
2356
 
2260
2357
  // src/utils/errors.ts
2261
- var COMMAND_REFERENCE = {
2262
- map: "Resumo do projeto (sem target)",
2263
- areas: "Listar todas as \xE1reas (sem target)",
2264
- area: "Arquivos de uma \xE1rea espec\xEDfica",
2358
+ var COMMAND_REFERENCE_KEYS = ["map", "areas", "area", "suggest", "context", "impact", "dead", "find", "describe"];
2359
+ var COMMAND_DESCRIPTIONS = {
2360
+ map: "Resumo do projeto",
2361
+ areas: "Listar todas as areas",
2362
+ area: "Arquivos de uma area especifica",
2265
2363
  suggest: "O que ler antes de editar",
2266
2364
  context: "API/assinaturas de um arquivo",
2267
2365
  impact: "Quem usa este arquivo",
2268
- dead: "C\xF3digo morto (sem target)"
2366
+ dead: "Codigo morto",
2367
+ find: "Buscar simbolos no codigo",
2368
+ describe: "Buscar areas por descricao"
2269
2369
  };
2270
- function getCommandReferenceSection(excludeCommand) {
2370
+ function getCommandReferenceSection(ctx, excludeCommand) {
2271
2371
  let out = `
2272
- \u{1F4CC} Comandos \xFAteis:
2372
+ \u{1F4CC} Comandos uteis:
2273
2373
  `;
2274
- for (const [cmd, desc] of Object.entries(COMMAND_REFERENCE)) {
2374
+ for (const cmd of COMMAND_REFERENCE_KEYS) {
2275
2375
  if (cmd !== excludeCommand) {
2276
- out += ` ai-tool ${cmd.padEnd(10)} ${desc}
2376
+ const desc = COMMAND_DESCRIPTIONS[cmd];
2377
+ out += ` \u2192 ${hint(cmd, ctx)} - ${desc}
2277
2378
  `;
2278
2379
  }
2279
2380
  }
2280
2381
  return out;
2281
2382
  }
2282
2383
  function formatFileNotFound(options) {
2283
- const { target, allFiles, command } = options;
2384
+ const { target, allFiles, command, ctx = "cli" } = options;
2284
2385
  const similarFiles = findSimilar(target, allFiles, {
2285
2386
  maxDistance: 3,
2286
2387
  limit: 5,
@@ -2288,14 +2389,20 @@ function formatFileNotFound(options) {
2288
2389
  });
2289
2390
  const bestMatch = findBestMatch(target, allFiles, extractFileName);
2290
2391
  let out = `
2291
- \u274C Arquivo n\xE3o encontrado: "${target}"
2392
+ \u274C Arquivo nao encontrado: "${target}"
2292
2393
 
2293
2394
  `;
2294
2395
  out += `\u{1F4CA} Total de arquivos indexados: ${allFiles.length}
2295
2396
 
2296
2397
  `;
2297
- if (bestMatch) {
2298
- out += `\u{1F4A1} Voc\xEA quis dizer?
2398
+ if (bestMatch && command) {
2399
+ out += `\u{1F4A1} Voce quis dizer?
2400
+ `;
2401
+ out += ` \u2192 ${hint(command, ctx, { "<arquivo>": bestMatch, "<termo>": bestMatch })}
2402
+
2403
+ `;
2404
+ } else if (bestMatch) {
2405
+ out += `\u{1F4A1} Voce quis dizer?
2299
2406
  `;
2300
2407
  out += ` \u2192 ${bestMatch}
2301
2408
 
@@ -2318,15 +2425,15 @@ function formatFileNotFound(options) {
2318
2425
  `;
2319
2426
  out += ` \u2022 Ou apenas o nome do arquivo: Header
2320
2427
  `;
2321
- out += ` \u2022 Verifique se o arquivo est\xE1 em uma pasta inclu\xEDda no scan
2428
+ out += ` \u2022 Verifique se o arquivo esta em uma pasta incluida no scan
2322
2429
  `;
2323
2430
  if (command) {
2324
- out += getCommandReferenceSection(command);
2431
+ out += getCommandReferenceSection(ctx, command);
2325
2432
  }
2326
2433
  return out;
2327
2434
  }
2328
2435
  function formatAreaNotFound(options) {
2329
- const { target, availableAreas } = options;
2436
+ const { target, availableAreas, ctx = "cli" } = options;
2330
2437
  const areaIds = availableAreas.map((a) => a.id);
2331
2438
  const bestMatchId = findBestMatch(target, areaIds);
2332
2439
  const similarAreaIds = findSimilar(target, areaIds, {
@@ -2334,18 +2441,18 @@ function formatAreaNotFound(options) {
2334
2441
  limit: 5
2335
2442
  });
2336
2443
  let out = `
2337
- \u274C \xC1rea n\xE3o encontrada: "${target}"
2444
+ \u274C Area nao encontrada: "${target}"
2338
2445
 
2339
2446
  `;
2340
2447
  if (bestMatchId) {
2341
- out += `\u{1F4A1} Voc\xEA quis dizer?
2448
+ out += `\u{1F4A1} Voce quis dizer?
2342
2449
  `;
2343
- out += ` \u2192 ai-tool area ${bestMatchId}
2450
+ out += ` \u2192 ${hint("area", ctx, { "<nome>": bestMatchId })}
2344
2451
 
2345
2452
  `;
2346
2453
  }
2347
2454
  if (availableAreas.length > 0) {
2348
- out += `\u{1F4E6} \xC1reas dispon\xEDveis:
2455
+ out += `\u{1F4E6} Areas disponiveis:
2349
2456
 
2350
2457
  `;
2351
2458
  if (similarAreaIds.length > 0 && !bestMatchId) {
@@ -2374,67 +2481,57 @@ function formatAreaNotFound(options) {
2374
2481
  }
2375
2482
  out += `\u{1F4D6} Dicas:
2376
2483
  `;
2377
- out += ` \u2022 Use o ID exato da \xE1rea (ex: ai-tool area auth)
2484
+ out += ` \u2192 ${hint("areas", ctx)} - listar todas as areas
2378
2485
  `;
2379
- out += ` \u2022 Use 'ai-tool areas' para listar todas as \xE1reas
2486
+ out += ` \u2192 ${hint("describe", ctx)} - buscar areas por descricao
2380
2487
  `;
2381
- out += ` \u2022 IDs s\xE3o case-sensitive (Auth \u2260 auth)
2382
- `;
2383
- out += `
2384
- \u{1F4CC} Comandos relacionados:
2385
- `;
2386
- out += ` ai-tool areas Listar todas as \xE1reas
2387
- `;
2388
- out += ` ai-tool map Ver estrutura do projeto
2488
+ out += ` \u2192 IDs sao case-sensitive (Auth \u2260 auth)
2389
2489
  `;
2390
2490
  return out;
2391
2491
  }
2392
- function formatMissingTarget(command) {
2492
+ function formatMissingTarget(command, ctx = "cli") {
2393
2493
  let out = `
2394
- \u274C Erro: par\xE2metro "target" \xE9 OBRIGAT\xD3RIO para o comando "${command}".
2494
+ \u274C Erro: parametro "target" e OBRIGATORIO para o comando "${command}".
2395
2495
 
2396
2496
  `;
2397
2497
  out += `\u{1F4DD} Exemplos:
2398
2498
  `;
2399
2499
  if (command === "area") {
2400
- out += ` ai-tool area auth
2500
+ out += ` ${hint("area", ctx, { "<nome>": "auth" })}
2401
2501
  `;
2402
- out += ` ai-tool area dashboard
2403
- `;
2404
- out += ` ai-tool area billing --type=hook
2502
+ out += ` ${hint("area", ctx, { "<nome>": "dashboard" })}
2405
2503
 
2406
2504
  `;
2407
- out += `\u{1F4A1} Use 'ai-tool areas' para listar todas as \xE1reas dispon\xEDveis.
2505
+ out += `\u{1F4A1} ${hint("areas", ctx)} - listar todas as areas disponiveis
2408
2506
  `;
2409
2507
  } else {
2410
- out += ` ai-tool ${command} useAuth
2411
- `;
2412
- out += ` ai-tool ${command} Button.tsx
2508
+ out += ` ${hint(command, ctx, { "<arquivo>": "useAuth", "<termo>": "useAuth" })}
2413
2509
  `;
2414
- out += ` ai-tool ${command} src/hooks/useAuth.ts
2510
+ out += ` ${hint(command, ctx, { "<arquivo>": "Button.tsx", "<termo>": "Button" })}
2415
2511
  `;
2416
2512
  }
2417
- out += getCommandReferenceSection(command);
2513
+ out += getCommandReferenceSection(ctx, command);
2418
2514
  return out;
2419
2515
  }
2420
- function formatInvalidCommand(command) {
2421
- const validCommands = Object.keys(COMMAND_REFERENCE);
2516
+ function formatInvalidCommand(command, ctx = "cli") {
2517
+ const validCommands = Object.keys(COMMAND_DESCRIPTIONS);
2422
2518
  const bestMatch = findBestMatch(command, validCommands);
2423
2519
  let out = `
2424
- \u274C Comando inv\xE1lido: "${command}"
2520
+ \u274C Comando invalido: "${command}"
2425
2521
 
2426
2522
  `;
2427
2523
  if (bestMatch) {
2428
- out += `\u{1F4A1} Voc\xEA quis dizer?
2524
+ out += `\u{1F4A1} Voce quis dizer?
2429
2525
  `;
2430
- out += ` \u2192 ai-tool ${bestMatch}
2526
+ out += ` \u2192 ${hint(bestMatch, ctx)}
2431
2527
 
2432
2528
  `;
2433
2529
  }
2434
- out += `\u{1F4CC} Comandos dispon\xEDveis:
2530
+ out += `\u{1F4CC} Comandos disponiveis:
2435
2531
  `;
2436
- for (const [cmd, desc] of Object.entries(COMMAND_REFERENCE)) {
2437
- out += ` ai-tool ${cmd.padEnd(10)} ${desc}
2532
+ for (const cmd of COMMAND_REFERENCE_KEYS) {
2533
+ const desc = COMMAND_DESCRIPTIONS[cmd];
2534
+ out += ` \u2192 ${hint(cmd, ctx)} - ${desc}
2438
2535
  `;
2439
2536
  }
2440
2537
  return out;
@@ -2490,10 +2587,10 @@ function findTargetFile(target, allFiles) {
2490
2587
  }
2491
2588
 
2492
2589
  // src/integrations/git.ts
2493
- import { existsSync as existsSync5 } from "fs";
2590
+ import { existsSync as existsSync6 } from "fs";
2494
2591
  import { execSync as execSync2 } from "child_process";
2495
2592
  function hasGitRepo(cwd) {
2496
- return existsSync5(cwd + "/.git");
2593
+ return existsSync6(cwd + "/.git");
2497
2594
  }
2498
2595
  async function getCommitsForFile(filePath, cwd, limit = 10) {
2499
2596
  if (!hasGitRepo(cwd)) {
@@ -2532,6 +2629,7 @@ async function getCommitsForFile(filePath, cwd, limit = 10) {
2532
2629
  async function impact(target, options = {}) {
2533
2630
  const { cwd, format } = parseCommandOptions(options);
2534
2631
  const useCache = options.cache !== false;
2632
+ const ctx = options.ctx || "cli";
2535
2633
  if (!target) {
2536
2634
  throw new Error("Target \xE9 obrigat\xF3rio. Exemplo: ai-tool impact src/components/Button.tsx");
2537
2635
  }
@@ -2577,7 +2675,7 @@ async function impact(target, options = {}) {
2577
2675
  }
2578
2676
  const targetPath = findTargetFile(target, allFiles);
2579
2677
  if (!targetPath) {
2580
- return formatFileNotFound({ target, allFiles, command: "impact" });
2678
+ return formatFileNotFound({ target, allFiles, command: "impact", ctx });
2581
2679
  }
2582
2680
  const { directUpstream, indirectUpstream, directDownstream, indirectDownstream } = calculateDependencies(targetPath, graph);
2583
2681
  const dependingOn = [...directUpstream, ...indirectUpstream];
@@ -2610,7 +2708,7 @@ async function impact(target, options = {}) {
2610
2708
  suggestions,
2611
2709
  gitHistory
2612
2710
  };
2613
- return formatOutput(result, format, formatImpactText, fromCache);
2711
+ return formatOutput(result, format, (r) => formatImpactText(r, ctx), fromCache);
2614
2712
  } catch (error) {
2615
2713
  const message = error instanceof Error ? error.message : String(error);
2616
2714
  throw new Error(`Erro ao executar impact: ${message}`);
@@ -2772,6 +2870,7 @@ async function suggest(target, options = {}) {
2772
2870
  const { cwd, format } = parseCommandOptions(options);
2773
2871
  const useCache = options.cache !== false;
2774
2872
  const limit = options.limit || 10;
2873
+ const ctx = options.ctx || "cli";
2775
2874
  if (!target) {
2776
2875
  throw new Error("Target e obrigatorio. Exemplo: ai-tool suggest src/components/Button.tsx");
2777
2876
  }
@@ -2813,7 +2912,7 @@ async function suggest(target, options = {}) {
2813
2912
  }
2814
2913
  const targetPath = findTargetFile(target, allFiles);
2815
2914
  if (!targetPath) {
2816
- return formatFileNotFound({ target, allFiles, command: "suggest" });
2915
+ return formatFileNotFound({ target, allFiles, command: "suggest", ctx });
2817
2916
  }
2818
2917
  const suggestions = collectSuggestions(targetPath, graph, allFiles, limit);
2819
2918
  const testSuggestions = generateTestSuggestions(suggestions, allFiles);
@@ -2825,7 +2924,7 @@ async function suggest(target, options = {}) {
2825
2924
  suggestions,
2826
2925
  testSuggestions
2827
2926
  };
2828
- return formatOutput(result, format, formatSuggestText, fromCache);
2927
+ return formatOutput(result, format, (r) => formatSuggestText(r, ctx), fromCache);
2829
2928
  } catch (error) {
2830
2929
  const message = error instanceof Error ? error.message : String(error);
2831
2930
  throw new Error(`Erro ao executar suggest: ${message}`);
@@ -3020,8 +3119,8 @@ function generateTestSuggestions(suggestions, allFiles) {
3020
3119
  }
3021
3120
 
3022
3121
  // src/commands/context.ts
3023
- import { existsSync as existsSync6, readdirSync as readdirSync3, statSync as statSync3 } from "fs";
3024
- import { join as join6, resolve as resolve2, basename, extname as extname3 } from "path";
3122
+ import { existsSync as existsSync7, readdirSync as readdirSync3, statSync as statSync3 } from "fs";
3123
+ import { join as join7, resolve as resolve2, basename, extname as extname3 } from "path";
3025
3124
  import { SyntaxKind as SyntaxKind3 } from "ts-morph";
3026
3125
 
3027
3126
  // src/ts/extractor.ts
@@ -3257,7 +3356,7 @@ import { SyntaxKind as SyntaxKind2 } from "ts-morph";
3257
3356
 
3258
3357
  // src/ts/index.ts
3259
3358
  import { readdirSync as readdirSync2, statSync as statSync2 } from "fs";
3260
- import { join as join5, extname as extname2 } from "path";
3359
+ import { join as join6, extname as extname2 } from "path";
3261
3360
  import { Project as Project2 } from "ts-morph";
3262
3361
 
3263
3362
  // src/utils/logger.ts
@@ -3372,7 +3471,7 @@ function getAllCodeFiles(dir, files = [], baseDir = dir) {
3372
3471
  try {
3373
3472
  const entries = readdirSync2(dir);
3374
3473
  for (const entry of entries) {
3375
- const fullPath = join5(dir, entry);
3474
+ const fullPath = join6(dir, entry);
3376
3475
  if (IGNORED_DIRS.has(entry) || entry.startsWith(".")) {
3377
3476
  continue;
3378
3477
  }
@@ -3888,6 +3987,7 @@ function indexProject(cwd) {
3888
3987
  // src/commands/context.ts
3889
3988
  async function context(target, options = {}) {
3890
3989
  const { cwd, format } = parseCommandOptions(options);
3990
+ const ctx = options.ctx || "cli";
3891
3991
  if (!target) {
3892
3992
  throw new Error("Target e obrigatorio. Exemplo: ai-tool context src/components/Button.tsx");
3893
3993
  }
@@ -3895,7 +3995,7 @@ async function context(target, options = {}) {
3895
3995
  const targetPath = findTargetFile2(target, cwd);
3896
3996
  if (!targetPath) {
3897
3997
  const allFiles = getAllCodeFiles2(cwd);
3898
- return formatFileNotFound({ target, allFiles, command: "context" });
3998
+ return formatFileNotFound({ target, allFiles, command: "context", ctx });
3899
3999
  }
3900
4000
  const project = createProject(cwd);
3901
4001
  const absolutePath = resolve2(cwd, targetPath);
@@ -3933,7 +4033,7 @@ async function context(target, options = {}) {
3933
4033
  types,
3934
4034
  constants: constants.length > 0 ? constants : void 0
3935
4035
  };
3936
- return formatOutput(result, format, formatContextText);
4036
+ return formatOutput(result, format, (r) => formatContextText(r, ctx));
3937
4037
  } catch (error) {
3938
4038
  const message = error instanceof Error ? error.message : String(error);
3939
4039
  throw new Error(`Erro ao executar context: ${message}`);
@@ -3943,12 +4043,12 @@ var CODE_EXTENSIONS3 = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".
3943
4043
  function findTargetFile2(target, cwd) {
3944
4044
  const normalizedTarget = target.replace(/\\/g, "/");
3945
4045
  const directPath = resolve2(cwd, normalizedTarget);
3946
- if (existsSync6(directPath) && isCodeFile2(directPath)) {
4046
+ if (existsSync7(directPath) && isCodeFile2(directPath)) {
3947
4047
  return normalizedTarget;
3948
4048
  }
3949
4049
  for (const ext of CODE_EXTENSIONS3) {
3950
4050
  const withExt = directPath + ext;
3951
- if (existsSync6(withExt)) {
4051
+ if (existsSync7(withExt)) {
3952
4052
  return normalizedTarget + ext;
3953
4053
  }
3954
4054
  }
@@ -3978,7 +4078,7 @@ function getAllCodeFiles2(dir, files = [], baseDir = dir) {
3978
4078
  try {
3979
4079
  const entries = readdirSync3(dir);
3980
4080
  for (const entry of entries) {
3981
- const fullPath = join6(dir, entry);
4081
+ const fullPath = join7(dir, entry);
3982
4082
  if (shouldIgnore(entry)) {
3983
4083
  continue;
3984
4084
  }
@@ -4015,10 +4115,32 @@ async function areaContext(areaName, options = {}) {
4015
4115
  const cwd = options.cwd || process.cwd();
4016
4116
  const format = options.format || "text";
4017
4117
  const useCache = options.cache !== false;
4118
+ const ctx = options.ctx || "cli";
4018
4119
  if (!areaName) {
4019
4120
  throw new Error("Nome da \xE1rea \xE9 obrigat\xF3rio. Exemplo: ai-tool context --area=auth");
4020
4121
  }
4021
4122
  try {
4123
+ if (!configExists(cwd) || Object.keys(readConfig(cwd).areas).length === 0) {
4124
+ let out = `\u26A0\uFE0F Nenhuma area configurada neste projeto.
4125
+
4126
+ `;
4127
+ out += `O comando area_context requer areas configuradas em .analyze/areas.config.json
4128
+ `;
4129
+ out += `Para configurar:
4130
+ `;
4131
+ out += ` 1. ${hint("areas_init", ctx)} - gerar arquivo de configuracao
4132
+ `;
4133
+ out += ` 2. Edite .analyze/areas.config.json com as areas do projeto
4134
+
4135
+ `;
4136
+ out += `Enquanto isso, use:
4137
+ `;
4138
+ out += ` \u2192 ${hint("context", ctx)} - ver assinaturas de um arquivo especifico
4139
+ `;
4140
+ out += ` \u2192 ${hint("find", ctx)} - buscar simbolos no codigo
4141
+ `;
4142
+ return out;
4143
+ }
4022
4144
  const config = readConfig(cwd);
4023
4145
  let index;
4024
4146
  if (useCache && isCacheValid(cwd)) {
@@ -4062,7 +4184,7 @@ async function areaContext(areaName, options = {}) {
4062
4184
  if (format === "json") {
4063
4185
  return JSON.stringify({ error: `Area nao encontrada: "${areaName}"`, availableAreas: areaList });
4064
4186
  }
4065
- return formatAreaNotFound({ target: areaName, availableAreas: areaList });
4187
+ return formatAreaNotFound({ target: areaName, availableAreas: areaList, ctx });
4066
4188
  }
4067
4189
  const types = [];
4068
4190
  const hooks = [];
@@ -4168,7 +4290,7 @@ async function areaContext(areaName, options = {}) {
4168
4290
  if (format === "json") {
4169
4291
  return JSON.stringify(result, null, 2);
4170
4292
  }
4171
- return formatAreaContextText(result);
4293
+ return formatAreaContextText(result, ctx);
4172
4294
  } catch (error) {
4173
4295
  const message = error instanceof Error ? error.message : String(error);
4174
4296
  throw new Error(`Erro ao executar context --area: ${message}`);
@@ -4195,7 +4317,7 @@ function findRealAreaIdFromIndex(target, areaFiles, config) {
4195
4317
 
4196
4318
  // src/commands/areas.ts
4197
4319
  import { readdirSync as readdirSync4, statSync as statSync4 } from "fs";
4198
- import { join as join7, extname as extname4 } from "path";
4320
+ import { join as join8, extname as extname4 } from "path";
4199
4321
  var CODE_EXTENSIONS4 = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
4200
4322
  var IGNORED_DIRS2 = /* @__PURE__ */ new Set([
4201
4323
  "node_modules",
@@ -4212,6 +4334,7 @@ var IGNORED_DIRS2 = /* @__PURE__ */ new Set([
4212
4334
  async function areas(options = {}) {
4213
4335
  const cwd = options.cwd || process.cwd();
4214
4336
  const format = options.format || "text";
4337
+ const ctx = options.ctx || "cli";
4215
4338
  try {
4216
4339
  const config = readConfig(cwd);
4217
4340
  const allFiles = getAllCodeFiles3(cwd);
@@ -4273,7 +4396,7 @@ async function areas(options = {}) {
4273
4396
  if (format === "json") {
4274
4397
  return JSON.stringify(result, null, 2);
4275
4398
  }
4276
- return formatAreasText(result);
4399
+ return formatAreasText(result, ctx);
4277
4400
  } catch (error) {
4278
4401
  const message = error instanceof Error ? error.message : String(error);
4279
4402
  throw new Error(`Erro ao executar areas: ${message}`);
@@ -4283,7 +4406,7 @@ function getAllCodeFiles3(dir, files = [], baseDir = dir) {
4283
4406
  try {
4284
4407
  const entries = readdirSync4(dir);
4285
4408
  for (const entry of entries) {
4286
- const fullPath = join7(dir, entry);
4409
+ const fullPath = join8(dir, entry);
4287
4410
  if (IGNORED_DIRS2.has(entry) || entry.startsWith(".")) {
4288
4411
  continue;
4289
4412
  }
@@ -4308,7 +4431,7 @@ function getAllCodeFiles3(dir, files = [], baseDir = dir) {
4308
4431
 
4309
4432
  // src/commands/area.ts
4310
4433
  import { readdirSync as readdirSync5, statSync as statSync5 } from "fs";
4311
- import { join as join8, extname as extname5 } from "path";
4434
+ import { join as join9, extname as extname5 } from "path";
4312
4435
  var CODE_EXTENSIONS5 = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
4313
4436
  var IGNORED_DIRS3 = /* @__PURE__ */ new Set([
4314
4437
  "node_modules",
@@ -4357,10 +4480,32 @@ async function area(target, options = {}) {
4357
4480
  const format = options.format || "text";
4358
4481
  const filterType = options.type;
4359
4482
  const full = options.full ?? false;
4483
+ const ctx = options.ctx || "cli";
4360
4484
  if (!target) {
4361
4485
  throw new Error("Nome da \xE1rea \xE9 obrigat\xF3rio. Exemplo: ai-tool area auth");
4362
4486
  }
4363
4487
  try {
4488
+ if (!configExists(cwd) || Object.keys(readConfig(cwd).areas).length === 0) {
4489
+ let out = `\u26A0\uFE0F Nenhuma area configurada neste projeto.
4490
+
4491
+ `;
4492
+ out += `O comando area requer areas configuradas em .analyze/areas.config.json
4493
+ `;
4494
+ out += `Para configurar:
4495
+ `;
4496
+ out += ` 1. ${hint("areas_init", ctx)} - gerar arquivo de configuracao
4497
+ `;
4498
+ out += ` 2. Edite .analyze/areas.config.json com as areas do projeto
4499
+
4500
+ `;
4501
+ out += `Enquanto isso, use:
4502
+ `;
4503
+ out += ` \u2192 ${hint("map", ctx)} - ver estrutura do projeto
4504
+ `;
4505
+ out += ` \u2192 ${hint("find", ctx)} - buscar simbolos no codigo
4506
+ `;
4507
+ return out;
4508
+ }
4364
4509
  const config = readConfig(cwd);
4365
4510
  const allFiles = getAllCodeFiles4(cwd);
4366
4511
  const resolvedTarget = resolveAreaId(target, config, allFiles);
@@ -4390,7 +4535,7 @@ async function area(target, options = {}) {
4390
4535
  }
4391
4536
  if (areaFiles.length === 0) {
4392
4537
  const availableAreas = getAvailableAreas(filteredFiles, config);
4393
- return formatAreaNotFound2(target, availableAreas);
4538
+ return formatAreaNotFound2(target, availableAreas, ctx);
4394
4539
  }
4395
4540
  const byCategory = {};
4396
4541
  const categories = {};
@@ -4427,7 +4572,7 @@ async function area(target, options = {}) {
4427
4572
  if (format === "json") {
4428
4573
  return JSON.stringify(result, null, 2);
4429
4574
  }
4430
- const output = formatAreaDetailText(result, { full, filterType });
4575
+ const output = formatAreaDetailText(result, { full, filterType }, ctx);
4431
4576
  return nameConversionMsg + output;
4432
4577
  } catch (error) {
4433
4578
  const message = error instanceof Error ? error.message : String(error);
@@ -4462,14 +4607,14 @@ function getAvailableAreas(allFiles, config) {
4462
4607
  }
4463
4608
  return [...areaCounts.entries()].map(([id, count]) => ({ id, count })).sort((a, b) => b.count - a.count);
4464
4609
  }
4465
- function formatAreaNotFound2(target, availableAreas) {
4466
- return formatAreaNotFound({ target, availableAreas });
4610
+ function formatAreaNotFound2(target, availableAreas, ctx = "cli") {
4611
+ return formatAreaNotFound({ target, availableAreas, ctx });
4467
4612
  }
4468
4613
  function getAllCodeFiles4(dir, files = [], baseDir = dir) {
4469
4614
  try {
4470
4615
  const entries = readdirSync5(dir);
4471
4616
  for (const entry of entries) {
4472
- const fullPath = join8(dir, entry);
4617
+ const fullPath = join9(dir, entry);
4473
4618
  if (IGNORED_DIRS3.has(entry) || entry.startsWith(".")) {
4474
4619
  continue;
4475
4620
  }
@@ -4494,7 +4639,7 @@ function getAllCodeFiles4(dir, files = [], baseDir = dir) {
4494
4639
 
4495
4640
  // src/commands/areas-init.ts
4496
4641
  import { readdirSync as readdirSync6, statSync as statSync6 } from "fs";
4497
- import { join as join9, extname as extname6 } from "path";
4642
+ import { join as join10, extname as extname6 } from "path";
4498
4643
  var CODE_EXTENSIONS6 = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
4499
4644
  var IGNORED_DIRS4 = /* @__PURE__ */ new Set([
4500
4645
  "node_modules",
@@ -4510,7 +4655,7 @@ var IGNORED_DIRS4 = /* @__PURE__ */ new Set([
4510
4655
  ]);
4511
4656
  function createInitialConfig(files) {
4512
4657
  const suggestedIgnore = detectSuggestedIgnorePatterns(files);
4513
- const framework = detectFramework(files);
4658
+ const framework = detectFramework2(files);
4514
4659
  return {
4515
4660
  $schema: "./areas.schema.json",
4516
4661
  version: "1.0.0",
@@ -4524,7 +4669,7 @@ function createInitialConfig(files) {
4524
4669
  }
4525
4670
  };
4526
4671
  }
4527
- function detectFramework(files) {
4672
+ function detectFramework2(files) {
4528
4673
  const hasAppDir = files.some((f) => f.startsWith("app/"));
4529
4674
  const hasPagesDir = files.some((f) => f.startsWith("pages/"));
4530
4675
  const hasSrcDir = files.some((f) => f.startsWith("src/"));
@@ -4679,7 +4824,7 @@ Ou edite manualmente o arquivo existente.
4679
4824
  const allFiles = getAllCodeFiles5(cwd);
4680
4825
  const newConfig = createInitialConfig(allFiles);
4681
4826
  writeConfig(cwd, newConfig);
4682
- const framework = detectFramework(allFiles);
4827
+ const framework = detectFramework2(allFiles);
4683
4828
  const frameworkName = {
4684
4829
  "nextjs-app": "Next.js (App Router)",
4685
4830
  "nextjs-pages": "Next.js (Pages Router)",
@@ -4783,7 +4928,7 @@ function getAllCodeFiles5(dir, files = [], baseDir = dir) {
4783
4928
  try {
4784
4929
  const entries = readdirSync6(dir);
4785
4930
  for (const entry of entries) {
4786
- const fullPath = join9(dir, entry);
4931
+ const fullPath = join10(dir, entry);
4787
4932
  if (IGNORED_DIRS4.has(entry) || entry.startsWith(".")) {
4788
4933
  continue;
4789
4934
  }
@@ -4814,6 +4959,7 @@ async function functions(options = {}) {
4814
4959
  const format = options.format || "text";
4815
4960
  const useCache = options.cache !== false;
4816
4961
  const filterTrigger = options.trigger;
4962
+ const ctx = options.ctx || "cli";
4817
4963
  if (!isFirebaseProject(cwd)) {
4818
4964
  const errorMsg = "Este nao e um projeto Firebase (nao encontrou .firebaserc ou firebase.json)";
4819
4965
  if (format === "json") {
@@ -4824,11 +4970,11 @@ async function functions(options = {}) {
4824
4970
  out += `
4825
4971
  \u{1F4A1} Comandos disponiveis para este projeto:
4826
4972
  `;
4827
- out += ` \u2192 ai-tool map - ver estrutura do projeto
4973
+ out += ` \u2192 ${hint("map", ctx)} - ver estrutura do projeto
4828
4974
  `;
4829
- out += ` \u2192 ai-tool find <termo> - buscar simbolos no codigo
4975
+ out += ` \u2192 ${hint("find", ctx)} - buscar simbolos no codigo
4830
4976
  `;
4831
- out += ` \u2192 ai-tool areas - listar areas funcionais
4977
+ out += ` \u2192 ${hint("areas", ctx)} - listar areas funcionais
4832
4978
  `;
4833
4979
  return out;
4834
4980
  }
@@ -4915,13 +5061,13 @@ async function functions(options = {}) {
4915
5061
  if (format === "json") {
4916
5062
  return JSON.stringify(result, null, 2);
4917
5063
  }
4918
- return formatFunctionsText(result);
5064
+ return formatFunctionsText(result, ctx);
4919
5065
  } catch (error) {
4920
5066
  const message = error instanceof Error ? error.message : String(error);
4921
5067
  throw new Error(`Erro ao executar functions: ${message}`);
4922
5068
  }
4923
5069
  }
4924
- function formatFunctionsText(result) {
5070
+ function formatFunctionsText(result, ctx = "cli") {
4925
5071
  let out = "";
4926
5072
  out += `
4927
5073
  `;
@@ -4938,42 +5084,35 @@ function formatFunctionsText(result) {
4938
5084
  `;
4939
5085
  out += ` Exportadas: ${result.summary.exported}
4940
5086
  `;
4941
- if (result.summary.total > 0) {
4942
- out += `
4943
- \u{1F4A1} Filtros dispon\xEDveis:
4944
- `;
4945
- out += ` ai-tool functions --trigger=onCall
4946
- `;
4947
- out += ` ai-tool functions --trigger=onDocumentCreated
4948
- `;
4949
- }
4950
5087
  out += `
4951
5088
  `;
4952
5089
  if (result.summary.total === 0) {
4953
5090
  out += ` \u26A0\uFE0F NENHUMA CLOUD FUNCTION DETECTADA
4954
5091
 
4955
5092
  `;
4956
- out += ` Poss\xEDveis causas:
5093
+ out += ` Possiveis causas:
4957
5094
  `;
4958
- out += ` 1. O projeto n\xE3o \xE9 Firebase (n\xE3o encontrou .firebaserc ou firebase.json)
5095
+ out += ` 1. O projeto nao e Firebase (nao encontrou .firebaserc ou firebase.json)
4959
5096
  `;
4960
- out += ` 2. N\xE3o h\xE1 arquivo functions/src/index.ts
5097
+ out += ` 2. Nao ha arquivo functions/src/index.ts
4961
5098
  `;
4962
- out += ` 3. Os triggers n\xE3o usam padr\xF5es v2 (onCall, onDocumentCreated, etc)
5099
+ out += ` 3. Os triggers nao usam padroes v2 (onCall, onDocumentCreated, etc)
4963
5100
  `;
4964
- out += ` 4. O cache est\xE1 desatualizado (ex: atualizou o ai-tool recentemente)
4965
- `;
4966
- out += ` \u2192 Tente: ai-tool functions --no-cache
5101
+ out += ` 4. O cache esta desatualizado
4967
5102
 
4968
5103
  `;
4969
- out += ` Padr\xF5es suportados:
5104
+ out += ` Padroes suportados:
4970
5105
  `;
4971
5106
  out += ` export const minhaFunc = onCall((request) => { ... })
4972
5107
  `;
4973
5108
  out += ` export const minhaFunc = onDocumentCreated("path", (event) => { ... })
4974
5109
 
4975
5110
  `;
4976
- out += ` Documenta\xE7\xE3o: https://firebase.google.com/docs/functions
5111
+ out += `\u{1F4A1} Dicas:
5112
+ `;
5113
+ out += ` \u2192 ${hint("map", ctx)} - ver estrutura do projeto
5114
+ `;
5115
+ out += ` \u2192 ${hint("find", ctx)} - buscar simbolos no codigo
4977
5116
  `;
4978
5117
  return out;
4979
5118
  }
@@ -5043,6 +5182,7 @@ function formatFunctionsText(result) {
5043
5182
  out += `
5044
5183
  `;
5045
5184
  }
5185
+ out += nextSteps("functions", ctx);
5046
5186
  return out;
5047
5187
  }
5048
5188
  function getTriggerIcon(trigger) {
@@ -5060,6 +5200,8 @@ function getTriggerIcon(trigger) {
5060
5200
  }
5061
5201
 
5062
5202
  // src/commands/find.ts
5203
+ import { readFileSync as readFileSync4 } from "fs";
5204
+ import { join as join11 } from "path";
5063
5205
  async function find(query, options = {}) {
5064
5206
  const { cwd, format } = parseCommandOptions(options);
5065
5207
  const filterType = options.type || "all";
@@ -5067,6 +5209,7 @@ async function find(query, options = {}) {
5067
5209
  const defOnly = options.def ?? false;
5068
5210
  const refsOnly = options.refs ?? false;
5069
5211
  const useCache = options.cache !== false;
5212
+ const ctx = options.ctx || "cli";
5070
5213
  const listAllMode = !query && defOnly && filterType && filterType !== "all";
5071
5214
  if (!query && !listAllMode) {
5072
5215
  throw new Error("Query \xE9 obrigat\xF3ria. Exemplo: ai-tool find useAuth\n Ou use --def para listar todos de um tipo: ai-tool find --type=trigger --def");
@@ -5119,10 +5262,10 @@ async function find(query, options = {}) {
5119
5262
  if (format === "json") {
5120
5263
  return JSON.stringify({ error: `Nenhum arquivo encontrado na area "${filterArea}"`, availableAreas: areaList });
5121
5264
  }
5122
- return formatAreaNotFound({ target: filterArea, availableAreas: areaList });
5265
+ return formatAreaNotFound({ target: filterArea, availableAreas: areaList, ctx });
5123
5266
  }
5124
5267
  }
5125
- const matches = searchInIndex(index, query, filterType, allowedFiles);
5268
+ const matches = searchInIndex(index, query, filterType, allowedFiles, cwd);
5126
5269
  let definition = null;
5127
5270
  let references = [];
5128
5271
  for (const match of matches) {
@@ -5165,13 +5308,13 @@ async function find(query, options = {}) {
5165
5308
  fromCache
5166
5309
  };
5167
5310
  const allSymbolNames = Object.keys(index.symbolsByName);
5168
- return formatOutput(result, format, (r) => formatFindText(r, "cli", allSymbolNames), fromCache);
5311
+ return formatOutput(result, format, (r) => formatFindText(r, ctx, allSymbolNames), fromCache);
5169
5312
  } catch (error) {
5170
5313
  const message = error instanceof Error ? error.message : String(error);
5171
5314
  throw new Error(`Erro ao executar find: ${message}`);
5172
5315
  }
5173
5316
  }
5174
- function searchInIndex(index, query, filterType, allowedFiles) {
5317
+ function searchInIndex(index, query, filterType, allowedFiles, cwd) {
5175
5318
  const matches = [];
5176
5319
  const queryLower = query?.toLowerCase() || "";
5177
5320
  const processedSymbols = /* @__PURE__ */ new Set();
@@ -5224,6 +5367,45 @@ function searchInIndex(index, query, filterType, allowedFiles) {
5224
5367
  }
5225
5368
  }
5226
5369
  }
5370
+ if (!listAllMode && query) {
5371
+ const importFiles = matches.filter((m) => m.matchType === "import").map((m) => m.file);
5372
+ const baseCwd = cwd || "";
5373
+ const MAX_USAGE_FILES = 10;
5374
+ const MAX_USAGES_PER_FILE = 3;
5375
+ for (const filePath of importFiles.slice(0, MAX_USAGE_FILES)) {
5376
+ try {
5377
+ const fullPath = baseCwd ? join11(baseCwd, filePath) : filePath;
5378
+ const content = readFileSync4(fullPath, "utf-8");
5379
+ const lines = content.split("\n");
5380
+ const usageRegex = new RegExp(`\\b${escapeRegex(query)}\\b`);
5381
+ let usagesFound = 0;
5382
+ for (let i = 0; i < lines.length && usagesFound < MAX_USAGES_PER_FILE; i++) {
5383
+ const line = lines[i].trim();
5384
+ if (line.startsWith("import ") || line.startsWith("export ") || line.startsWith("//") || line.startsWith("*") || line.startsWith("/*")) {
5385
+ continue;
5386
+ }
5387
+ if (usageRegex.test(line)) {
5388
+ const key = `usage:${filePath}:${i + 1}:${query}`;
5389
+ if (processedSymbols.has(key)) continue;
5390
+ processedSymbols.add(key);
5391
+ const fileData = index.files[filePath];
5392
+ const codeLine = line.length > 100 ? line.substring(0, 100) + "..." : line;
5393
+ matches.push({
5394
+ file: filePath,
5395
+ line: i + 1,
5396
+ column: 0,
5397
+ code: codeLine,
5398
+ matchType: "usage",
5399
+ symbolType: inferSymbolTypeFromName(query),
5400
+ category: fileData?.category || "other"
5401
+ });
5402
+ usagesFound++;
5403
+ }
5404
+ }
5405
+ } catch {
5406
+ }
5407
+ }
5408
+ }
5227
5409
  matches.sort((a, b) => {
5228
5410
  const order = { definition: 0, import: 1, usage: 2 };
5229
5411
  const orderDiff = order[a.matchType] - order[b.matchType];
@@ -5232,6 +5414,9 @@ function searchInIndex(index, query, filterType, allowedFiles) {
5232
5414
  });
5233
5415
  return matches;
5234
5416
  }
5417
+ function escapeRegex(str) {
5418
+ return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
5419
+ }
5235
5420
  function matchesType(kind, filter) {
5236
5421
  if (filter === "all") return true;
5237
5422
  switch (filter) {
@@ -5327,7 +5512,6 @@ export {
5327
5512
  map,
5328
5513
  dead,
5329
5514
  deadFix,
5330
- COMMAND_REFERENCE,
5331
5515
  formatFileNotFound,
5332
5516
  formatAreaNotFound,
5333
5517
  formatMissingTarget,