@justmpm/supergrep 0.1.1 → 0.2.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.
@@ -6,9 +6,9 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
6
6
  import { z } from "zod";
7
7
 
8
8
  // src/tools/find.ts
9
- import { parse } from "@ast-grep/napi";
10
- import { readFile, readdir } from "fs/promises";
11
- import { join, relative, resolve, extname } from "path";
9
+ import { findInFiles } from "@ast-grep/napi";
10
+ import { relative, resolve } from "path";
11
+ import { stat } from "fs/promises";
12
12
 
13
13
  // src/utils/lang.ts
14
14
  import { Lang } from "@ast-grep/napi";
@@ -65,35 +65,6 @@ function langName(lang) {
65
65
  };
66
66
  return friendly[langStr] ?? langStr;
67
67
  }
68
- function isSupportedExtension(filePath) {
69
- const ext = filePath.slice(filePath.lastIndexOf(".")).toLowerCase();
70
- return SUPPORTED_EXTENSIONS.has(ext);
71
- }
72
- var IGNORED_EXTENSIONS_SUBSTRINGS = [
73
- ".min.js",
74
- ".min.css",
75
- ".bundle.js",
76
- ".chunk.js",
77
- ".map",
78
- ".d.ts"
79
- ];
80
- function shouldIgnoreFile(filePath) {
81
- const lower = filePath.toLowerCase();
82
- for (const ext of IGNORED_EXTENSIONS_SUBSTRINGS) {
83
- if (lower.includes(ext)) return true;
84
- }
85
- return false;
86
- }
87
- var IGNORED_DIRS = [
88
- "node_modules",
89
- "dist",
90
- "build",
91
- ".git",
92
- ".next",
93
- ".turbo",
94
- "coverage",
95
- "out"
96
- ];
97
68
 
98
69
  // src/tools/find.ts
99
70
  var MULTI_META_RE = /\$\$\$([A-Z_][A-Z0-9_]*)/g;
@@ -102,33 +73,47 @@ async function findPattern(options) {
102
73
  const startTime = Date.now();
103
74
  const warnings = [];
104
75
  const cwd = options.cwd ?? process.cwd();
105
- const lang = resolveLangForOptions(options, cwd, warnings);
106
- if (!lang) {
76
+ let lang;
77
+ if (options.lang) {
78
+ lang = resolveLang(options.lang);
79
+ if (!lang) {
80
+ warnings.push(`Linguagem "${options.lang}" nao reconhecida. Usando autodeteccao...`);
81
+ }
82
+ }
83
+ const searchPath = resolve(cwd, options.path ?? ".");
84
+ try {
85
+ await stat(searchPath);
86
+ } catch {
87
+ warnings.push(`Path nao encontrado: ${searchPath}. Usando diretorio atual.`);
107
88
  throw new LanguageNotDetectedError(options.lang ?? "desconhecida");
108
89
  }
109
- validatePattern(options.pattern, lang);
110
- const searchDir = resolve(cwd, options.path ?? ".");
111
- const files = await findCodeFiles(searchDir, cwd, lang);
112
- warnings.push(...files.warnings);
113
90
  const metaVars = extractMetaVarInfo(options.pattern);
91
+ const napiConfig = {
92
+ rule: { pattern: options.pattern }
93
+ };
94
+ const findConfig = {
95
+ paths: [searchPath],
96
+ matcher: napiConfig
97
+ };
98
+ if (lang) {
99
+ findConfig.languageGlobs = langToGlobs(lang);
100
+ }
101
+ const langForSearch = lang ?? resolveLang("typescript");
114
102
  const matches = [];
115
- for (const filePath of files.paths) {
116
- try {
117
- const source = await readFile(filePath, "utf-8");
118
- const ast = parse(lang, source);
119
- const root = ast.root();
120
- const foundNodes = root.findAll(options.pattern);
121
- for (const node of foundNodes) {
103
+ try {
104
+ const fileResults = await findInFilesWrapper(langForSearch, findConfig);
105
+ for (const { file, nodes } of fileResults) {
106
+ for (const node of nodes) {
122
107
  const range = node.range();
108
+ const text = node.text();
123
109
  const match = {
124
- file: relative(cwd, filePath).replace(/\\/g, "/"),
110
+ file: relative(cwd, file).replace(/\\/g, "/"),
125
111
  line: range.start.line,
126
112
  column: range.start.column,
127
113
  endLine: range.end.line,
128
114
  endColumn: range.end.column,
129
- text: node.text(),
130
- metaVariables: {},
131
- context: extractContextLines(source, range.start.line, 2)
115
+ text,
116
+ metaVariables: {}
132
117
  };
133
118
  for (const { name, isMulti } of metaVars) {
134
119
  if (isMulti) {
@@ -145,19 +130,23 @@ async function findPattern(options) {
145
130
  }
146
131
  matches.push(match);
147
132
  }
148
- } catch {
149
- continue;
150
133
  }
134
+ } catch (err) {
135
+ const msg = err instanceof Error ? err.message : String(err);
136
+ if (lang) {
137
+ throw new PatternParseError(options.pattern, lang);
138
+ }
139
+ throw new Error(`Erro na busca: ${msg}`);
151
140
  }
152
- const uniqueFiles = new Set(matches.map((m) => m.file));
141
+ const filesWithMatchesSet = new Set(matches.map((m) => m.file));
153
142
  const executionTimeMs = Date.now() - startTime;
154
143
  return {
155
144
  result: {
156
145
  pattern: options.pattern,
157
- lang,
146
+ lang: langForSearch,
158
147
  matches,
159
- filesScanned: files.paths.length,
160
- filesWithMatches: uniqueFiles.size,
148
+ filesScanned: matches.length > 0 ? filesWithMatchesSet.size : 0,
149
+ filesWithMatches: filesWithMatchesSet.size,
161
150
  executionTimeMs
162
151
  },
163
152
  warnings
@@ -185,92 +174,56 @@ function extractMetaVarInfo(pattern) {
185
174
  }
186
175
  return result;
187
176
  }
188
- function extractContextLines(source, line, contextLines) {
189
- const lines = source.split("\n");
190
- const start = Math.max(0, line - contextLines);
191
- const end = Math.min(lines.length, line + contextLines + 1);
192
- return lines.slice(start, end);
193
- }
194
- function resolveLangForOptions(options, _cwd, warnings) {
195
- if (options.lang) {
196
- const lang = resolveLang(options.lang);
197
- if (!lang) {
198
- warnings.push(`Linguagem "${options.lang}" nao reconhecida. Tentando autodeteccao...`);
199
- } else {
200
- return lang;
201
- }
202
- }
203
- if (options.path) {
204
- const ext = extname(options.path).toLowerCase();
205
- if (ext && isSupportedExtension(options.path)) {
206
- const detected = detectLangFromFile(options.path);
207
- if (detected) return detected;
208
- }
209
- }
210
- return resolveLang("typescript");
177
+ var IGNORED_DIR_PATTERNS = [
178
+ /[/\\]node_modules[/\\]/,
179
+ /[/\\]dist[/\\]/,
180
+ /[/\\]build[/\\]/,
181
+ /[/\\]\.git[/\\]/,
182
+ /[/\\]\.next[/\\]/,
183
+ /[/\\]\.turbo[/\\]/,
184
+ /[/\\]coverage[/\\]/,
185
+ /[/\\]out[/\\]/
186
+ ];
187
+ function isIgnoredPath(filePath) {
188
+ const normalized = filePath.replace(/\\/g, "/");
189
+ const wrapped = `/${normalized}/`;
190
+ return IGNORED_DIR_PATTERNS.some((re) => re.test(wrapped));
211
191
  }
212
- function validatePattern(pattern, lang) {
213
- try {
214
- parse(lang, pattern);
215
- } catch {
216
- try {
217
- parse(lang, `const _x = ${pattern}`);
218
- } catch {
219
- throw new PatternParseError(pattern, lang);
192
+ async function findInFilesWrapper(lang, config) {
193
+ const results = [];
194
+ let callbacksReceived = 0;
195
+ const totalFiles = await findInFiles(
196
+ lang,
197
+ config,
198
+ (err, nodes) => {
199
+ callbacksReceived++;
200
+ if (err || nodes.length === 0) return;
201
+ const file = nodes[0].getRoot()?.filename() ?? "unknown";
202
+ if (isIgnoredPath(file)) return;
203
+ results.push({ file, nodes });
220
204
  }
205
+ );
206
+ while (callbacksReceived < totalFiles) {
207
+ await new Promise((r) => setTimeout(r, 10));
221
208
  }
209
+ return results;
222
210
  }
223
- async function findCodeFiles(searchDir, _cwd, _lang) {
224
- const warnings = [];
225
- try {
226
- const { stat: stat3 } = await import("fs/promises");
227
- const dirStat = await stat3(searchDir);
228
- if (dirStat.isFile()) {
229
- if (!isSupportedExtension(searchDir)) {
230
- const fileName = searchDir.split(/[/\\]/).pop() ?? searchDir;
231
- warnings.push(
232
- `Arquivo ${fileName}: extensao pode nao ser suportada para ${langName(_lang)}`
233
- );
234
- }
235
- return { paths: [searchDir], warnings };
236
- }
237
- } catch {
238
- warnings.push(`Path nao encontrado: ${searchDir}. Usando diretorio atual.`);
239
- return { paths: [], warnings };
240
- }
241
- const paths = [];
242
- async function walk(dir) {
243
- try {
244
- const entries = await readdir(dir, { withFileTypes: true });
245
- for (const entry of entries) {
246
- const fullPath = join(dir, entry.name);
247
- if (entry.isDirectory()) {
248
- if (IGNORED_DIRS.includes(entry.name) || entry.name.startsWith(".")) {
249
- continue;
250
- }
251
- await walk(fullPath);
252
- } else if (entry.isFile()) {
253
- if (shouldIgnoreFile(fullPath)) continue;
254
- if (!isSupportedExtension(fullPath)) continue;
255
- paths.push(fullPath);
256
- }
257
- }
258
- } catch {
259
- }
260
- }
261
- await walk(searchDir);
262
- if (paths.length > 5e3) {
263
- warnings.push(
264
- `Muitos arquivos encontrados (${paths.length}). Limitando a 5000. Use --path para focar em um diretorio.`
265
- );
266
- return { paths: paths.slice(0, 5e3), warnings };
267
- }
268
- if (paths.length === 0) {
269
- warnings.push(
270
- `Nenhum arquivo de codigo encontrado em: ${relative(_cwd, searchDir)}`
271
- );
211
+ function langToGlobs(lang) {
212
+ const langStr = String(lang);
213
+ switch (langStr) {
214
+ case "TypeScript":
215
+ return ["*.ts"];
216
+ case "JavaScript":
217
+ return ["*.js", "*.jsx", "*.mjs", "*.cjs"];
218
+ case "Tsx":
219
+ return ["*.tsx"];
220
+ case "Css":
221
+ return ["*.css", "*.scss", "*.less"];
222
+ case "Html":
223
+ return ["*.html", "*.htm"];
224
+ default:
225
+ return [];
272
226
  }
273
- return { paths, warnings };
274
227
  }
275
228
  var PatternParseError = class extends Error {
276
229
  pattern;
@@ -292,9 +245,9 @@ var LanguageNotDetectedError = class extends Error {
292
245
  };
293
246
 
294
247
  // src/tools/tree.ts
295
- import { parse as parse2 } from "@ast-grep/napi";
296
- import { readFile as readFile2, stat } from "fs/promises";
297
- import { resolve as resolve2, relative as relative2, extname as extname2 } from "path";
248
+ import { parse } from "@ast-grep/napi";
249
+ import { readFile, stat as stat2 } from "fs/promises";
250
+ import { resolve as resolve2, relative as relative2, extname } from "path";
298
251
  async function exploreTree(options) {
299
252
  const warnings = [];
300
253
  const cwd = options.cwd ?? process.cwd();
@@ -315,11 +268,11 @@ async function exploreTree(options) {
315
268
  } else if (options.path) {
316
269
  filePath = resolve2(cwd, options.path);
317
270
  try {
318
- await stat(filePath);
271
+ await stat2(filePath);
319
272
  } catch {
320
273
  throw new FileNotFoundError(filePath);
321
274
  }
322
- source = await readFile2(filePath, "utf-8");
275
+ source = await readFile(filePath, "utf-8");
323
276
  if (options.lang) {
324
277
  detectedLang = resolveLang(options.lang);
325
278
  if (!detectedLang) {
@@ -330,7 +283,7 @@ async function exploreTree(options) {
330
283
  detectedLang = detectLangFromFile(filePath);
331
284
  if (!detectedLang) {
332
285
  warnings.push(
333
- `Nao foi possivel detectar linguagem da extensao "${extname2(filePath)}". Usando TypeScript.`
286
+ `Nao foi possivel detectar linguagem da extensao "${extname(filePath)}". Usando TypeScript.`
334
287
  );
335
288
  detectedLang = resolveLang("typescript");
336
289
  }
@@ -341,7 +294,7 @@ async function exploreTree(options) {
341
294
  const lang = detectedLang;
342
295
  let ast;
343
296
  try {
344
- ast = parse2(lang, source);
297
+ ast = parse(lang, source);
345
298
  } catch (parseErr) {
346
299
  const msg = parseErr instanceof Error ? parseErr.message : String(parseErr);
347
300
  throw new TreeParseError(filePath, lang, msg);
@@ -393,9 +346,9 @@ var TreeParseError = class extends Error {
393
346
  };
394
347
 
395
348
  // src/tools/replace.ts
396
- import { parse as parse3 } from "@ast-grep/napi";
397
- import { readFile as readFile3, readdir as readdir2, stat as stat2 } from "fs/promises";
398
- import { join as join2, resolve as resolve3, relative as relative3 } from "path";
349
+ import { findInFiles as findInFiles2 } from "@ast-grep/napi";
350
+ import { resolve as resolve3, relative as relative3 } from "path";
351
+ import { stat as stat3 } from "fs/promises";
399
352
  var MULTI_META_RE2 = /\$\$\$([A-Z_][A-Z0-9_]*)/g;
400
353
  var SINGLE_META_RE2 = /(?<!\$)\$(?:\$\$)?([A-Z_][A-Z0-9_]*)/g;
401
354
  async function replacePreview(options) {
@@ -418,18 +371,28 @@ async function replacePreview(options) {
418
371
  } else {
419
372
  lang = resolveLang("typescript");
420
373
  }
421
- validateReplacePattern(options.pattern, lang);
422
- const searchDir = resolve3(cwd, options.path ?? ".");
423
- const files = await findCodeFiles2(searchDir);
374
+ const searchPath = resolve3(cwd, options.path ?? ".");
375
+ try {
376
+ await stat3(searchPath);
377
+ } catch {
378
+ throw new ReplaceLangError(
379
+ `Path nao encontrado: ${searchPath}`
380
+ );
381
+ }
424
382
  const metaVars = extractMetaVarInfo2(options.pattern);
383
+ const napiConfig = {
384
+ rule: { pattern: options.pattern }
385
+ };
386
+ const findConfig = {
387
+ paths: [searchPath],
388
+ matcher: napiConfig,
389
+ languageGlobs: langToGlobs2(lang)
390
+ };
425
391
  const changes = [];
426
- for (const filePath of files.paths) {
427
- try {
428
- const source = await readFile3(filePath, "utf-8");
429
- const ast = parse3(lang, source);
430
- const root = ast.root();
431
- const foundNodes = root.findAll(options.pattern);
432
- for (const node of foundNodes) {
392
+ try {
393
+ const fileResults = await findInFilesWrapper2(lang, findConfig);
394
+ for (const { file, nodes } of fileResults) {
395
+ for (const node of nodes) {
433
396
  const metaVarValues = {};
434
397
  for (const { name, isMulti } of metaVars) {
435
398
  if (isMulti) {
@@ -453,16 +416,16 @@ async function replacePreview(options) {
453
416
  }
454
417
  const range = node.range();
455
418
  changes.push({
456
- file: relative3(cwd, filePath).replace(/\\/g, "/"),
419
+ file: relative3(cwd, file).replace(/\\/g, "/"),
457
420
  line: range.start.line,
458
421
  column: range.start.column,
459
422
  original: node.text(),
460
423
  replacement: interpolated
461
424
  });
462
425
  }
463
- } catch {
464
- continue;
465
426
  }
427
+ } catch {
428
+ throw new ReplacePatternError(options.pattern, lang);
466
429
  }
467
430
  const uniqueFiles = new Set(changes.map((c) => c.file));
468
431
  return {
@@ -471,7 +434,7 @@ async function replacePreview(options) {
471
434
  rewrite: options.rewrite,
472
435
  lang,
473
436
  changes,
474
- filesScanned: files.paths.length,
437
+ filesScanned: changes.length > 0 ? uniqueFiles.size : 0,
475
438
  filesAffected: uniqueFiles.size
476
439
  },
477
440
  warnings
@@ -499,55 +462,56 @@ function extractMetaVarInfo2(pattern) {
499
462
  }
500
463
  return result;
501
464
  }
502
- function validateReplacePattern(pattern, lang) {
503
- try {
504
- parse3(lang, pattern);
505
- } catch {
506
- try {
507
- parse3(lang, `const _x = ${pattern}`);
508
- } catch {
509
- throw new ReplacePatternError(pattern, lang);
510
- }
511
- }
465
+ var IGNORED_DIR_PATTERNS2 = [
466
+ /[/\\]node_modules[/\\]/,
467
+ /[/\\]dist[/\\]/,
468
+ /[/\\]build[/\\]/,
469
+ /[/\\]\.git[/\\]/,
470
+ /[/\\]\.next[/\\]/,
471
+ /[/\\]\.turbo[/\\]/,
472
+ /[/\\]coverage[/\\]/,
473
+ /[/\\]out[/\\]/
474
+ ];
475
+ function isIgnoredPath2(filePath) {
476
+ const normalized = filePath.replace(/\\/g, "/");
477
+ const wrapped = `/${normalized}/`;
478
+ return IGNORED_DIR_PATTERNS2.some((re) => re.test(wrapped));
512
479
  }
513
- async function findCodeFiles2(searchDir) {
514
- const warnings = [];
515
- try {
516
- const dirStat = await stat2(searchDir);
517
- if (dirStat.isFile()) {
518
- return { paths: [searchDir], warnings };
519
- }
520
- } catch {
521
- return { paths: [], warnings };
522
- }
523
- const paths = [];
524
- async function walk(dir) {
525
- try {
526
- const entries = await readdir2(dir, { withFileTypes: true });
527
- for (const entry of entries) {
528
- const fullPath = join2(dir, entry.name);
529
- if (entry.isDirectory()) {
530
- if (IGNORED_DIRS.includes(entry.name) || entry.name.startsWith(".")) {
531
- continue;
532
- }
533
- await walk(fullPath);
534
- } else if (entry.isFile()) {
535
- if (shouldIgnoreFile(fullPath)) continue;
536
- if (!isSupportedExtension(fullPath)) continue;
537
- paths.push(fullPath);
538
- }
539
- }
540
- } catch {
480
+ async function findInFilesWrapper2(lang, config) {
481
+ const results = [];
482
+ let callbacksReceived = 0;
483
+ const totalFiles = await findInFiles2(
484
+ lang,
485
+ config,
486
+ (err, nodes) => {
487
+ callbacksReceived++;
488
+ if (err || nodes.length === 0) return;
489
+ const file = nodes[0].getRoot()?.filename() ?? "unknown";
490
+ if (isIgnoredPath2(file)) return;
491
+ results.push({ file, nodes });
541
492
  }
493
+ );
494
+ while (callbacksReceived < totalFiles) {
495
+ await new Promise((r) => setTimeout(r, 10));
542
496
  }
543
- await walk(searchDir);
544
- if (paths.length > 5e3) {
545
- warnings.push(
546
- `Muitos arquivos (${paths.length}). Limitando a 5000. Use --path para focar.`
547
- );
548
- return { paths: paths.slice(0, 5e3), warnings };
497
+ return results;
498
+ }
499
+ function langToGlobs2(lang) {
500
+ const langStr = String(lang);
501
+ switch (langStr) {
502
+ case "TypeScript":
503
+ return ["*.ts"];
504
+ case "JavaScript":
505
+ return ["*.js", "*.jsx", "*.mjs", "*.cjs"];
506
+ case "Tsx":
507
+ return ["*.tsx"];
508
+ case "Css":
509
+ return ["*.css", "*.scss", "*.less"];
510
+ case "Html":
511
+ return ["*.html", "*.htm"];
512
+ default:
513
+ return [];
549
514
  }
550
- return { paths, warnings };
551
515
  }
552
516
  var ReplacePatternError = class extends Error {
553
517
  pattern;
@@ -1052,10 +1016,18 @@ metavariaveis ($VAR, $$VAR, $$$VARS) como curingas que capturam partes dinamicas
1052
1016
  \u{1F4E6} LINGUAGENS SUPORTADAS (apenas 5):
1053
1017
  \u2022 typescript (.ts) \u2014 apenas .ts puro (sem JSX)
1054
1018
  \u2022 javascript (.js, .jsx, .mjs, .cjs)
1055
- \u2022 tsx (.tsx) \u2014 .tsx COM JSX/React (requer lang: 'tsx')
1019
+ \u2022 tsx (.tsx) \u2014 .tsx COM JSX/React
1056
1020
  \u2022 css (.css, .scss, .less)
1057
1021
  \u2022 html (.html, .htm)
1058
1022
 
1023
+ \u{1F916} AUTODETECCAO: Se o parametro 'lang' NAO for especificado, o motor
1024
+ detecta a linguagem automaticamente pela extensao de cada arquivo.
1025
+ Voce pode buscar em um diretorio com .ts e .tsx misturados \u2014 o motor
1026
+ usa o parser correto para cada arquivo.
1027
+
1028
+ Use 'lang' apenas quando quiser RESTRINGIR a busca a uma linguagem
1029
+ especifica (ex: forcar TSX em todo o diretorio).
1030
+
1059
1031
  \u26A0\uFE0F LIMITACAO IMPORTANTE: Apenas busca SINTAXICA. Nao resolve imports, nao
1060
1032
  entende tipos, nao segue referencias entre arquivos, nao faz analise de fluxo.
1061
1033
  Cada arquivo e analisado isoladamente. Para analise semantica, use ai-tool.
@@ -1109,7 +1081,7 @@ Workflow recomendado: supergrep_find \u2192 supergrep_tree \u2192 supergrep_repl
1109
1081
  "Padrao AST Grep na linguagem alvo. Ex: 'console.$METHOD($$$ARGS)', 'function $NAME($$$PARAMS) { $$$BODY }'"
1110
1082
  ),
1111
1083
  lang: z.string().optional().describe(
1112
- "Linguagem: 'typescript' (.ts), 'javascript' (.js), 'tsx' (.tsx), 'css' (.css), 'html' (.html). Default: typescript. Deixe vazio para autodeteccao por extensao."
1084
+ "Linguagem: 'typescript' (.ts), 'javascript' (.js), 'tsx' (.tsx), 'css' (.css), 'html' (.html). Opcional \u2014 se nao especificado, o motor autodetecta pela extensao de cada arquivo."
1113
1085
  ),
1114
1086
  path: z.string().optional().describe(
1115
1087
  "Arquivo ou diretorio onde buscar. Default: diretorio atual. Ex: 'src/', 'app/page.tsx'"
@@ -1168,6 +1140,10 @@ Cada estrutura de codigo vira um kind diferente na AST.
1168
1140
  \u{1F4A1} Como usar os kinds: ao ver call_expression no tree, voce pode buscar
1169
1141
  chamadas de funcao com o pattern: $FUNC($$$ARGS)
1170
1142
 
1143
+ \u{1F916} AUTODETECCAO: se usar 'path', a linguagem e detectada automaticamente
1144
+ pela extensao do arquivo. O parametro 'lang' so e necessario ao usar
1145
+ 'code' (snippet inline) ou para forcar uma linguagem especifica.
1146
+
1171
1147
  QUANDO USAR:
1172
1148
  - "Quais tipos de nos existem neste arquivo TypeScript?"
1173
1149
  - "Como escrever um pattern para capturar certas estruturas?"
@@ -1244,6 +1220,10 @@ apos a substituicao. Util para planejar refatoracoes em larga escala.
1244
1220
  O supergrep faz interpolacao manual: textos dos nos sao concatenados
1245
1221
  com ", " e injetados no lugar do $VAR no rewrite.
1246
1222
 
1223
+ \u{1F916} AUTODETECCAO DE LINGUAGEM: se 'lang' nao for especificado, o motor
1224
+ detecta automaticamente pela extensao de cada arquivo. Use 'lang' apenas
1225
+ para RESTRINGIR a busca a uma linguagem especifica.
1226
+
1247
1227
  QUANDO USAR:
1248
1228
  - "Como ficaria se eu trocasse console.log por logger.info?"
1249
1229
  - "Preview de substituir var por let em todo o projeto"
@@ -1264,7 +1244,7 @@ Workflow: supergrep_find \u2192 supergrep_replace (preview) \u2192 aplicar mudan
1264
1244
  "Texto de substituicao. Use $VAR para referenciar metavariaveis capturadas. Ex: 'logger.info($$$ARGS)'"
1265
1245
  ),
1266
1246
  lang: z.string().optional().describe(
1267
- "Linguagem: 'typescript', 'javascript', 'tsx', 'css', 'html'. Default: typescript."
1247
+ "Linguagem: 'typescript', 'javascript', 'tsx', 'css', 'html'. Opcional \u2014 se nao especificado, o motor autodetecta pela extensao de cada arquivo."
1268
1248
  ),
1269
1249
  path: z.string().optional().describe(
1270
1250
  "Arquivo ou diretorio onde buscar. Default: diretorio atual."
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  startMcpServer
4
- } from "./chunk-SENMQNTX.js";
4
+ } from "./chunk-5PJJZ4CK.js";
5
5
 
6
6
  // src/cli.ts
7
7
  startMcpServer().catch((err) => {
package/dist/index.d.ts CHANGED
@@ -33,7 +33,6 @@ declare function startMcpServer(): Promise<void>;
33
33
  * await startMcpServer();
34
34
  */
35
35
 
36
- /** Versao do pacote */
37
- declare const VERSION = "0.1.0";
36
+ declare const VERSION: string;
38
37
 
39
38
  export { VERSION, startMcpServer };
package/dist/index.js CHANGED
@@ -1,9 +1,12 @@
1
1
  import {
2
2
  startMcpServer
3
- } from "./chunk-SENMQNTX.js";
3
+ } from "./chunk-5PJJZ4CK.js";
4
4
 
5
5
  // src/index.ts
6
- var VERSION = "0.1.0";
6
+ import { createRequire } from "module";
7
+ var require2 = createRequire(import.meta.url);
8
+ var pkg = require2("../package.json");
9
+ var VERSION = pkg.version;
7
10
  export {
8
11
  VERSION,
9
12
  startMcpServer
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@justmpm/supergrep",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "description": "MCP server para busca estrutural de código com AST Grep. Encontra padrões de código com precisão sintática, ignorando formatação e comentários. Suporta 20+ linguagens via Tree-sitter.",
5
5
  "keywords": [
6
6
  "ast-grep",