@justmpm/ai-tool 3.18.0 → 3.20.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.
@@ -20,7 +20,7 @@ import {
20
20
  readConfig,
21
21
  recoveryHint,
22
22
  simplifyType
23
- } from "./chunk-DBABYIEY.js";
23
+ } from "./chunk-MEG5Q7XP.js";
24
24
 
25
25
  // src/commands/describe.ts
26
26
  var STOPWORDS = /* @__PURE__ */ new Set([
@@ -1233,7 +1233,7 @@ function extractPackageApiImpl(project, typeFiles, packagePath, limit, jsFallbac
1233
1233
  return { functions: [], types: [], constants: [], truncated: { functions: false, types: false, totalFunctions: 0, totalTypes: 0, shown: 0 } };
1234
1234
  }
1235
1235
  const originalFileCount = sourceFiles.length;
1236
- if (!jsFallback) {
1236
+ if (!jsFallback && nodeModulesDir) {
1237
1237
  const reExportedFiles = followReExports(
1238
1238
  project,
1239
1239
  sourceFiles,
@@ -1279,7 +1279,8 @@ function extractPackageApiImpl(project, typeFiles, packagePath, limit, jsFallbac
1279
1279
  }
1280
1280
  for (const fn of functions) {
1281
1281
  if (fn.name.startsWith("_")) continue;
1282
- if (fn.isExported || exportNames.has(fn.name) || jsFallback) {
1282
+ if (isLikelyMinified(fn.name)) continue;
1283
+ if (fn.isExported || exportNames.has(fn.name) || publicApiNames.has(fn.name) || jsFallback) {
1283
1284
  allFunctions.push({
1284
1285
  ...fn,
1285
1286
  sourceFile: relativeSource,
@@ -1289,14 +1290,16 @@ function extractPackageApiImpl(project, typeFiles, packagePath, limit, jsFallbac
1289
1290
  }
1290
1291
  for (const type of types) {
1291
1292
  if (type.name.startsWith("_")) continue;
1292
- if (type.isExported || exportNames.has(type.name) || jsFallback) {
1293
+ if (isLikelyMinified(type.name)) continue;
1294
+ if (type.isExported || exportNames.has(type.name) || publicApiNames.has(type.name) || jsFallback) {
1293
1295
  allTypes.push({ ...type, sourceFile: relativeSource });
1294
1296
  }
1295
1297
  }
1296
1298
  const constants = extractConstants(sourceFile, jsFallback);
1297
1299
  for (const constant of constants) {
1298
1300
  if (constant.name.startsWith("_")) continue;
1299
- if (constant.isExported || exportNames.has(constant.name) || jsFallback) {
1301
+ if (isLikelyMinified(constant.name)) continue;
1302
+ if (constant.isExported || exportNames.has(constant.name) || publicApiNames.has(constant.name) || jsFallback) {
1300
1303
  allConstants.push({ ...constant, sourceFile: relativeSource });
1301
1304
  }
1302
1305
  }
@@ -1344,6 +1347,9 @@ function extractConstants(sourceFile, includeAll = false) {
1344
1347
  }
1345
1348
  return constants;
1346
1349
  }
1350
+ function isLikelyMinified(name) {
1351
+ return name.length === 1;
1352
+ }
1347
1353
  function deduplicateByName(items) {
1348
1354
  const seen = /* @__PURE__ */ new Map();
1349
1355
  for (const item of items) {
@@ -1463,6 +1469,15 @@ async function depsInfo(packageName, options = {}) {
1463
1469
  }
1464
1470
  try {
1465
1471
  const result = readPackageJson(packageName, cwd);
1472
+ if (result.version === "0.0.0" && !packageName.startsWith("@") && packageName.includes("/")) {
1473
+ const basePkg = packageName.slice(0, packageName.indexOf("/"));
1474
+ try {
1475
+ const baseResult = readPackageJson(basePkg, cwd);
1476
+ result.version = baseResult.version;
1477
+ result.info.version = baseResult.version;
1478
+ } catch {
1479
+ }
1480
+ }
1466
1481
  const projectPkgPath = join3(cwd, "package.json");
1467
1482
  if (existsSync3(projectPkgPath)) {
1468
1483
  try {
@@ -1832,7 +1832,11 @@ function formatChangesText(result, ctx = "cli") {
1832
1832
  return out;
1833
1833
  }
1834
1834
  const targetLabel = result.target === "staged" ? "staged" : result.target === "unstaged" ? "unstaged" : "unstaged + staged";
1835
- out += `Files: ${result.summary.totalFiles} modified (${targetLabel}) | +${result.summary.totalAdded} -${result.summary.totalRemoved}
1835
+ let summaryLine = `Files: ${result.summary.totalFiles} modified (${targetLabel}) | +${result.summary.totalAdded} -${result.summary.totalRemoved}`;
1836
+ if (result.summary.totalNewFiles > 0) {
1837
+ summaryLine += ` | ${result.summary.totalNewFiles} new (untracked)`;
1838
+ }
1839
+ out += `${summaryLine}
1836
1840
  `;
1837
1841
  const kindCounts = {};
1838
1842
  for (const file of result.files) {
@@ -1876,26 +1880,45 @@ AFFECTED AREAS:
1876
1880
  }
1877
1881
  out += "\n";
1878
1882
  }
1879
- const semanticFiles = result.files.filter((f) => f.changes.length > 0);
1880
- const otherFiles = result.files.filter((f) => f.changes.length === 0);
1883
+ const semanticFiles = result.files.filter((f) => f.changes.length > 0 && !f.newFile);
1884
+ const newFiles = result.files.filter((f) => f.newFile);
1885
+ const otherFiles = result.files.filter((f) => f.changes.length === 0 && !f.newFile);
1881
1886
  const COMPACT_THRESHOLD = 10;
1882
- if (result.files.length > COMPACT_THRESHOLD) {
1887
+ const filesExceedThreshold = semanticFiles.length + newFiles.length > COMPACT_THRESHOLD;
1888
+ if (filesExceedThreshold) {
1883
1889
  out += `
1884
1890
  COMPACT MODE: Too many files. Use --file=<path> for details.
1885
1891
 
1886
1892
  `;
1887
- out += `Modified files:
1893
+ const modifiedCompact = result.files.filter((f) => !f.newFile);
1894
+ if (modifiedCompact.length > 0) {
1895
+ out += `Modified files:
1896
+ `;
1897
+ for (const file of modifiedCompact) {
1898
+ const changeCount = file.changes.length;
1899
+ out += ` ${file.path} (+${file.stats.added} -${file.stats.removed})`;
1900
+ if (changeCount > 0) {
1901
+ out += ` - ${changeCount} changes`;
1902
+ } else {
1903
+ out += ` - (no semantic changes)`;
1904
+ }
1905
+ out += `
1888
1906
  `;
1889
- for (const file of result.files) {
1890
- const changeCount = file.changes.length;
1891
- out += ` ${file.path} (+${file.stats.added} -${file.stats.removed})`;
1892
- if (changeCount > 0) {
1893
- out += ` - ${changeCount} changes`;
1894
- } else {
1895
- out += ` - (no semantic changes)`;
1896
1907
  }
1908
+ }
1909
+ if (newFiles.length > 0) {
1897
1910
  out += `
1911
+ New files (untracked):
1898
1912
  `;
1913
+ for (const file of newFiles) {
1914
+ const changeCount = file.changes.length;
1915
+ out += ` ${file.path} (+${file.stats.added} new)`;
1916
+ if (changeCount > 0) {
1917
+ out += ` - ${changeCount} symbols`;
1918
+ }
1919
+ out += `
1920
+ `;
1921
+ }
1899
1922
  }
1900
1923
  out += `
1901
1924
  Use: ${hint("changes", ctx)} --file=<arquivo>
@@ -1952,6 +1975,31 @@ Use: ${hint("changes", ctx)} --file=<arquivo>
1952
1975
  }
1953
1976
  }
1954
1977
  }
1978
+ if (newFiles.length > 0) {
1979
+ out += `
1980
+ NEW FILES (${newFiles.length}, untracked)
1981
+ `;
1982
+ for (const file of newFiles) {
1983
+ out += `
1984
+ ${file.path} (+${file.stats.added} lines)
1985
+ `;
1986
+ if (file.changes.length > 0) {
1987
+ for (const entry of file.changes) {
1988
+ const prefix = formatKindIcon(entry.kind);
1989
+ const detail = entry.detail ? ` - ${entry.detail}` : "";
1990
+ out += ` ${prefix} ${entry.name}${detail}
1991
+ `;
1992
+ if (entry.previewLines && entry.previewLines.length > 0) {
1993
+ for (const line of entry.previewLines) {
1994
+ const truncated = line.length > 80 ? line.substring(0, 77) + "..." : line;
1995
+ out += ` ${truncated}
1996
+ `;
1997
+ }
1998
+ }
1999
+ }
2000
+ }
2001
+ }
2002
+ }
1955
2003
  if (otherFiles.length > 0) {
1956
2004
  out += `
1957
2005
  OTHER FILES (${otherFiles.length}): `;
@@ -2346,10 +2394,22 @@ function formatDepsSearchText(result, ctx = "cli") {
2346
2394
  out += `
2347
2395
  `;
2348
2396
  }
2349
- const pluralTotal = result.summary.total !== 1 ? "s" : "";
2397
+ const shown = result.matches.length;
2398
+ const total = result.summary.total;
2399
+ const pluralTotal = total !== 1 ? "s" : "";
2350
2400
  const pluralFiles = result.summary.files !== 1 ? "s" : "";
2351
- out += `${result.summary.total} resultado${pluralTotal} em ${result.summary.files} arquivo${pluralFiles}
2401
+ if (shown < total) {
2402
+ out += `${shown} de ${total} resultado${pluralTotal} em ${result.summary.files} arquivo${pluralFiles}
2352
2403
  `;
2404
+ } else {
2405
+ out += `${total} resultado${pluralTotal} em ${result.summary.files} arquivo${pluralFiles}
2406
+ `;
2407
+ }
2408
+ if (total > 50) {
2409
+ out += `
2410
+ Muitos resultados encontrados. Refine a busca com termos mais especificos.
2411
+ `;
2412
+ }
2353
2413
  out += nextSteps("deps_search", ctx);
2354
2414
  return out;
2355
2415
  }
@@ -2687,12 +2747,16 @@ function expandMuiOverrideType(tsType, simplifiedText) {
2687
2747
  const typeMap = typeArgs[0];
2688
2748
  const propsProperty = typeMap.getProperty("props");
2689
2749
  if (propsProperty) {
2690
- const propsType = propsProperty.getType();
2691
- const props = propsType.getProperties();
2692
- if (props.length > 0) {
2693
- const propNames = props.slice(0, 12).map((p) => p.getName());
2694
- const suffix = props.length > 12 ? ", ..." : "";
2695
- return `{ ${propNames.join(", ")}${suffix} }`;
2750
+ const propsDecls = propsProperty.getDeclarations();
2751
+ const propsNode = propsDecls.length > 0 ? propsDecls[0] : void 0;
2752
+ if (propsNode) {
2753
+ const propsType = propsProperty.getTypeAtLocation(propsNode);
2754
+ const props = propsType.getProperties();
2755
+ if (props.length > 0) {
2756
+ const propNames = props.slice(0, 12).map((p) => p.getName());
2757
+ const suffix = props.length > 12 ? ", ..." : "";
2758
+ return `{ ${propNames.join(", ")}${suffix} }`;
2759
+ }
2696
2760
  }
2697
2761
  }
2698
2762
  }
@@ -5171,6 +5235,20 @@ function getDiffArgs(target) {
5171
5235
  return ["HEAD"];
5172
5236
  }
5173
5237
  }
5238
+ function getUntrackedFiles(cwd) {
5239
+ if (!hasGitRepo(cwd)) return [];
5240
+ try {
5241
+ const cmd = `git ls-files --others --exclude-standard`;
5242
+ const output = execSync2(cmd, {
5243
+ cwd,
5244
+ encoding: "utf-8",
5245
+ stdio: ["pipe", "pipe", "pipe"]
5246
+ });
5247
+ return output.trim().split("\n").filter((line) => line.trim() !== "").map((line) => line.trim());
5248
+ } catch {
5249
+ return [];
5250
+ }
5251
+ }
5174
5252
  function getChangedFiles(target, cwd) {
5175
5253
  if (!hasGitRepo(cwd)) return [];
5176
5254
  try {
@@ -7135,6 +7213,8 @@ function getTriggerIcon(trigger) {
7135
7213
 
7136
7214
  // src/commands/changes.ts
7137
7215
  import * as path from "path";
7216
+ import { readFileSync as readFileSync7 } from "fs";
7217
+ var UNTRACKED_PREVIEW_LINES = 20;
7138
7218
  async function changes(options = {}) {
7139
7219
  const { cwd, format } = parseCommandOptions(options);
7140
7220
  const ctx = options.ctx || "cli";
@@ -7144,13 +7224,15 @@ async function changes(options = {}) {
7144
7224
  }
7145
7225
  try {
7146
7226
  const changedFiles = getChangedFiles(target, cwd);
7147
- if (changedFiles.length === 0) {
7227
+ const untrackedFiles = getUntrackedFiles(cwd);
7228
+ if (changedFiles.length === 0 && untrackedFiles.length === 0) {
7148
7229
  const result2 = {
7149
7230
  version: "1.0.0",
7150
7231
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
7151
7232
  target,
7152
7233
  summary: {
7153
7234
  totalFiles: 0,
7235
+ totalNewFiles: 0,
7154
7236
  totalAdded: 0,
7155
7237
  totalRemoved: 0
7156
7238
  },
@@ -7162,9 +7244,15 @@ async function changes(options = {}) {
7162
7244
  const filesFiltered = changedFiles.filter(
7163
7245
  (f) => !DEFAULT_IGNORE.some((pattern) => f.includes(pattern))
7164
7246
  );
7247
+ const untrackedFiltered = untrackedFiles.filter(
7248
+ (f) => !DEFAULT_IGNORE.some((pattern) => f.includes(pattern))
7249
+ );
7165
7250
  const filesToProcess = options.file ? filesFiltered.filter(
7166
7251
  (f) => f.toLowerCase().includes(options.file.toLowerCase())
7167
7252
  ) : filesFiltered;
7253
+ const untrackedToProcess = options.file ? untrackedFiltered.filter(
7254
+ (f) => f.toLowerCase().includes(options.file.toLowerCase())
7255
+ ) : untrackedFiltered;
7168
7256
  const fileChanges = [];
7169
7257
  let totalAdded = 0;
7170
7258
  let totalRemoved = 0;
@@ -7191,14 +7279,50 @@ async function changes(options = {}) {
7191
7279
  changes: enrichedEntries
7192
7280
  });
7193
7281
  }
7282
+ for (const filePath of untrackedToProcess) {
7283
+ const fullFilePath = path.resolve(cwd, filePath);
7284
+ let lineCount = 0;
7285
+ try {
7286
+ const content = readFileSync7(fullFilePath, "utf-8");
7287
+ const lines = content.split("\n");
7288
+ lineCount = lines.length;
7289
+ const syntheticDiff = lines.slice(0, UNTRACKED_PREVIEW_LINES).map((line) => `+${line}`).join("\n");
7290
+ let entries = classifyChanges(syntheticDiff);
7291
+ if (entries.length === 0) {
7292
+ const ext = path.extname(filePath).toLowerCase();
7293
+ if (!CODE_EXTENSIONS2.has(ext)) {
7294
+ entries = extractGenericDiffPreview(syntheticDiff, filePath);
7295
+ }
7296
+ }
7297
+ const enrichedEntries = enrichWithJsDoc(entries, filePath, symbolsIndex);
7298
+ fileChanges.push({
7299
+ path: filePath,
7300
+ category: detectCategory(filePath),
7301
+ stats: { added: lineCount, removed: 0 },
7302
+ changes: enrichedEntries,
7303
+ newFile: true
7304
+ });
7305
+ totalAdded += lineCount;
7306
+ } catch {
7307
+ fileChanges.push({
7308
+ path: filePath,
7309
+ category: detectCategory(filePath),
7310
+ stats: { added: 0, removed: 0 },
7311
+ changes: [],
7312
+ newFile: true
7313
+ });
7314
+ }
7315
+ }
7194
7316
  const affectedAreas = buildAffectedAreas(fileChanges, cwd);
7195
7317
  const totalForSummary = options.file ? fileChanges.length : changedFiles.length;
7318
+ const totalNewForSummary = options.file ? fileChanges.filter((f) => f.newFile).length : untrackedFiles.length;
7196
7319
  const result = {
7197
7320
  version: "1.0.0",
7198
7321
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
7199
7322
  target,
7200
7323
  summary: {
7201
7324
  totalFiles: totalForSummary,
7325
+ totalNewFiles: totalNewForSummary,
7202
7326
  totalAdded,
7203
7327
  totalRemoved
7204
7328
  },
@@ -7694,7 +7818,7 @@ function extractGenericDiffPreview(diffText, filePath) {
7694
7818
  }
7695
7819
 
7696
7820
  // src/commands/find.ts
7697
- import { existsSync as existsSync10, readFileSync as readFileSync7 } from "fs";
7821
+ import { existsSync as existsSync10, readFileSync as readFileSync8 } from "fs";
7698
7822
  import { join as join11 } from "path";
7699
7823
 
7700
7824
  // src/cache/gitHistory.ts
@@ -7894,7 +8018,7 @@ function searchInIndex(index, query, filterType, allowedFiles, cwd) {
7894
8018
  if (!existsSync10(fullPath)) {
7895
8019
  continue;
7896
8020
  }
7897
- const content = readFileSync7(fullPath, "utf-8");
8021
+ const content = readFileSync8(fullPath, "utf-8");
7898
8022
  const lines = content.split("\n");
7899
8023
  usageFilesScanned++;
7900
8024
  const usageRegex = new RegExp(`\\b${escapeRegex3(query)}\\b`);
package/dist/cli.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  depsInfo,
5
5
  depsSearch,
6
6
  describe
7
- } from "./chunk-5HTCZRJR.js";
7
+ } from "./chunk-6COZBZSS.js";
8
8
  import {
9
9
  VERSION,
10
10
  area,
@@ -20,7 +20,7 @@ import {
20
20
  impact,
21
21
  map,
22
22
  suggest
23
- } from "./chunk-DBABYIEY.js";
23
+ } from "./chunk-MEG5Q7XP.js";
24
24
 
25
25
  // src/cli.ts
26
26
  import { resolve } from "path";
@@ -131,7 +131,7 @@ async function main() {
131
131
  }
132
132
  }
133
133
  if (flags.mcp) {
134
- const { startMcpServer } = await import("./server-DB7YY6SP.js");
134
+ const { startMcpServer } = await import("./server-W7QUWBDG.js");
135
135
  await startMcpServer();
136
136
  return;
137
137
  }
package/dist/index.d.ts CHANGED
@@ -398,6 +398,8 @@ interface FileChange {
398
398
  removed: number;
399
399
  };
400
400
  changes: ChangeEntry[];
401
+ /** Arquivo untracked (nunca commitado) */
402
+ newFile?: boolean;
401
403
  }
402
404
  interface ChangesOptions extends CommandOptions {
403
405
  target?: "staged" | "unstaged" | "all";
@@ -416,6 +418,7 @@ interface ChangesResult {
416
418
  target: "staged" | "unstaged" | "all";
417
419
  summary: {
418
420
  totalFiles: number;
421
+ totalNewFiles: number;
419
422
  totalAdded: number;
420
423
  totalRemoved: number;
421
424
  };
package/dist/index.js CHANGED
@@ -47,7 +47,7 @@ import {
47
47
  setFileDescription,
48
48
  suggest,
49
49
  writeConfig
50
- } from "./chunk-DBABYIEY.js";
50
+ } from "./chunk-MEG5Q7XP.js";
51
51
  export {
52
52
  VERSION,
53
53
  area,
@@ -3,7 +3,7 @@ import {
3
3
  depsInfo,
4
4
  depsSearch,
5
5
  describe
6
- } from "./chunk-5HTCZRJR.js";
6
+ } from "./chunk-6COZBZSS.js";
7
7
  import {
8
8
  VERSION,
9
9
  area,
@@ -19,7 +19,7 @@ import {
19
19
  map,
20
20
  recoveryHint,
21
21
  suggest
22
- } from "./chunk-DBABYIEY.js";
22
+ } from "./chunk-MEG5Q7XP.js";
23
23
 
24
24
  // src/mcp/server.ts
25
25
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@justmpm/ai-tool",
3
- "version": "3.18.0",
3
+ "version": "3.20.0",
4
4
  "description": "Ferramenta de análise de dependências e impacto para projetos TypeScript/JavaScript. Usa Skott + Knip internamente. Inclui busca por descrição, integração Git e testes inteligentes.",
5
5
  "keywords": [
6
6
  "dependency-analysis",