@justmpm/ai-tool 3.22.1 → 3.22.2
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.
|
@@ -1832,10 +1832,22 @@ 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
|
-
|
|
1835
|
+
const parts = [];
|
|
1836
|
+
parts.push(`Files: ${result.summary.totalFiles} modified (${targetLabel})`);
|
|
1837
|
+
parts.push(`+${result.summary.totalAdded} -${result.summary.totalRemoved}`);
|
|
1836
1838
|
if (result.summary.totalNewFiles > 0) {
|
|
1837
|
-
|
|
1839
|
+
parts.push(`${result.summary.totalNewFiles} new (untracked, ${result.summary.totalUntrackedLines} lines)`);
|
|
1840
|
+
}
|
|
1841
|
+
if (result.summary.totalRenames > 0) {
|
|
1842
|
+
parts.push(`${result.summary.totalRenames} renamed`);
|
|
1843
|
+
}
|
|
1844
|
+
if (result.summary.totalAddedFiles > 0) {
|
|
1845
|
+
parts.push(`${result.summary.totalAddedFiles} added`);
|
|
1838
1846
|
}
|
|
1847
|
+
if (result.summary.totalDeletedFiles > 0) {
|
|
1848
|
+
parts.push(`${result.summary.totalDeletedFiles} deleted`);
|
|
1849
|
+
}
|
|
1850
|
+
let summaryLine = parts.join(" | ");
|
|
1839
1851
|
out += `${summaryLine}
|
|
1840
1852
|
`;
|
|
1841
1853
|
const kindCounts = {};
|
|
@@ -1859,11 +1871,11 @@ function formatChangesText(result, ctx = "cli") {
|
|
|
1859
1871
|
};
|
|
1860
1872
|
const kindParts = [];
|
|
1861
1873
|
for (const [kind, counts] of Object.entries(kindCounts)) {
|
|
1862
|
-
const
|
|
1863
|
-
if (counts.added > 0)
|
|
1864
|
-
if (counts.modified > 0)
|
|
1865
|
-
if (counts.removed > 0)
|
|
1866
|
-
if (
|
|
1874
|
+
const parts2 = [];
|
|
1875
|
+
if (counts.added > 0) parts2.push(`+${counts.added}`);
|
|
1876
|
+
if (counts.modified > 0) parts2.push(`~${counts.modified}`);
|
|
1877
|
+
if (counts.removed > 0) parts2.push(`-${counts.removed}`);
|
|
1878
|
+
if (parts2.length > 0) kindParts.push(`${kindLabels[kind]}: ${parts2.join(" ")}`);
|
|
1867
1879
|
}
|
|
1868
1880
|
if (kindParts.length > 0) {
|
|
1869
1881
|
out += `${kindParts.join(" | ")}
|
|
@@ -1891,10 +1903,12 @@ COMPACT MODE: Too many files. Use --file=<path> for details.
|
|
|
1891
1903
|
|
|
1892
1904
|
`;
|
|
1893
1905
|
const modifiedCompact = result.files.filter((f) => !f.newFile);
|
|
1894
|
-
|
|
1906
|
+
const renamedCompact = modifiedCompact.filter((f) => f.renamed);
|
|
1907
|
+
const otherModifiedCompact = modifiedCompact.filter((f) => !f.renamed);
|
|
1908
|
+
if (otherModifiedCompact.length > 0) {
|
|
1895
1909
|
out += `Modified files:
|
|
1896
1910
|
`;
|
|
1897
|
-
for (const file of
|
|
1911
|
+
for (const file of otherModifiedCompact) {
|
|
1898
1912
|
const changeCount = file.changes.length;
|
|
1899
1913
|
out += ` ${file.path} (+${file.stats.added} -${file.stats.removed})`;
|
|
1900
1914
|
if (changeCount > 0) {
|
|
@@ -1903,6 +1917,20 @@ COMPACT MODE: Too many files. Use --file=<path> for details.
|
|
|
1903
1917
|
out += ` - (no semantic changes)`;
|
|
1904
1918
|
}
|
|
1905
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 += `
|
|
1906
1934
|
`;
|
|
1907
1935
|
}
|
|
1908
1936
|
}
|
|
@@ -2000,6 +2028,24 @@ NEW FILES (${newFiles.length}, untracked)
|
|
|
2000
2028
|
}
|
|
2001
2029
|
}
|
|
2002
2030
|
}
|
|
2031
|
+
const renamedFiles = semanticFiles.filter((f) => f.renamed);
|
|
2032
|
+
if (renamedFiles.length > 0) {
|
|
2033
|
+
out += `
|
|
2034
|
+
RENAMED FILES (${renamedFiles.length})
|
|
2035
|
+
`;
|
|
2036
|
+
for (const file of renamedFiles) {
|
|
2037
|
+
out += ` ${file.renamedFrom} -> ${file.path} (+${file.stats.added} -${file.stats.removed})
|
|
2038
|
+
`;
|
|
2039
|
+
if (file.changes.length > 0) {
|
|
2040
|
+
for (const entry of file.changes) {
|
|
2041
|
+
const prefix = formatKindIcon(entry.kind);
|
|
2042
|
+
const detail = entry.detail ? ` - ${entry.detail}` : "";
|
|
2043
|
+
out += ` ${prefix} ${entry.name}${detail}
|
|
2044
|
+
`;
|
|
2045
|
+
}
|
|
2046
|
+
}
|
|
2047
|
+
}
|
|
2048
|
+
}
|
|
2003
2049
|
if (otherFiles.length > 0) {
|
|
2004
2050
|
out += `
|
|
2005
2051
|
OTHER FILES (${otherFiles.length}):
|
|
@@ -5301,26 +5347,12 @@ function getUntrackedFiles(cwd) {
|
|
|
5301
5347
|
return [];
|
|
5302
5348
|
}
|
|
5303
5349
|
}
|
|
5304
|
-
function
|
|
5305
|
-
if (!hasGitRepo(cwd)) return [];
|
|
5306
|
-
try {
|
|
5307
|
-
const diffArgs = getDiffArgs(target);
|
|
5308
|
-
const cmd = `git diff --name-only ${diffArgs.join(" ")}`;
|
|
5309
|
-
const output = execSync2(cmd, {
|
|
5310
|
-
cwd,
|
|
5311
|
-
encoding: "utf-8",
|
|
5312
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
5313
|
-
});
|
|
5314
|
-
return output.trim().split("\n").filter((line) => line.trim() !== "").map((line) => line.trim());
|
|
5315
|
-
} catch {
|
|
5316
|
-
return [];
|
|
5317
|
-
}
|
|
5318
|
-
}
|
|
5319
|
-
function getDiffForFile(filePath, target, cwd) {
|
|
5350
|
+
function getFullDiffText(target, cwd, filePath) {
|
|
5320
5351
|
if (!hasGitRepo(cwd)) return "";
|
|
5321
5352
|
try {
|
|
5322
5353
|
const diffArgs = getDiffArgs(target);
|
|
5323
|
-
const
|
|
5354
|
+
const fileArg = filePath ? ` -- "${filePath}"` : "";
|
|
5355
|
+
const cmd = `git diff --unified=10${fileArg} ${diffArgs.join(" ")}`;
|
|
5324
5356
|
const output = execSync2(cmd, {
|
|
5325
5357
|
cwd,
|
|
5326
5358
|
encoding: "utf-8",
|
|
@@ -5331,28 +5363,6 @@ function getDiffForFile(filePath, target, cwd) {
|
|
|
5331
5363
|
return "";
|
|
5332
5364
|
}
|
|
5333
5365
|
}
|
|
5334
|
-
function getDiffStats(filePath, target, cwd) {
|
|
5335
|
-
if (!hasGitRepo(cwd)) return null;
|
|
5336
|
-
try {
|
|
5337
|
-
const diffArgs = getDiffArgs(target);
|
|
5338
|
-
const cmd = `git diff --numstat ${diffArgs.join(" ")} -- "${filePath}"`;
|
|
5339
|
-
const output = execSync2(cmd, {
|
|
5340
|
-
cwd,
|
|
5341
|
-
encoding: "utf-8",
|
|
5342
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
5343
|
-
});
|
|
5344
|
-
const line = output.trim().split("\n")[0];
|
|
5345
|
-
if (!line) return null;
|
|
5346
|
-
const parts = line.split(" ");
|
|
5347
|
-
if (parts.length < 2) return null;
|
|
5348
|
-
const added = parts[0] === "-" ? 0 : parseInt(parts[0], 10);
|
|
5349
|
-
const removed = parts[1] === "-" ? 0 : parseInt(parts[1], 10);
|
|
5350
|
-
if (Number.isNaN(added) || Number.isNaN(removed)) return null;
|
|
5351
|
-
return { added, removed };
|
|
5352
|
-
} catch {
|
|
5353
|
-
return null;
|
|
5354
|
-
}
|
|
5355
|
-
}
|
|
5356
5366
|
|
|
5357
5367
|
// src/commands/impact.ts
|
|
5358
5368
|
async function impact(target, options = {}) {
|
|
@@ -7266,6 +7276,7 @@ function getTriggerIcon(trigger) {
|
|
|
7266
7276
|
// src/commands/changes.ts
|
|
7267
7277
|
import * as path from "path";
|
|
7268
7278
|
import { readFileSync as readFileSync7 } from "fs";
|
|
7279
|
+
import parseGitDiff from "parse-git-diff";
|
|
7269
7280
|
var UNTRACKED_PREVIEW_LINES = 20;
|
|
7270
7281
|
async function changes(options = {}) {
|
|
7271
7282
|
const { cwd, format } = parseCommandOptions(options);
|
|
@@ -7275,59 +7286,55 @@ async function changes(options = {}) {
|
|
|
7275
7286
|
throw new Error("Nao e um repositorio Git. Execute este comando em um projeto com Git.");
|
|
7276
7287
|
}
|
|
7277
7288
|
try {
|
|
7278
|
-
const
|
|
7289
|
+
const diffText = getFullDiffText(target, cwd, options.file || void 0);
|
|
7279
7290
|
const untrackedFiles = getUntrackedFiles(cwd);
|
|
7280
|
-
if (changedFiles.length === 0 && untrackedFiles.length === 0) {
|
|
7281
|
-
const result2 = {
|
|
7282
|
-
version: "1.0.0",
|
|
7283
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7284
|
-
target,
|
|
7285
|
-
summary: {
|
|
7286
|
-
totalFiles: 0,
|
|
7287
|
-
totalNewFiles: 0,
|
|
7288
|
-
totalAdded: 0,
|
|
7289
|
-
totalRemoved: 0
|
|
7290
|
-
},
|
|
7291
|
-
files: []
|
|
7292
|
-
};
|
|
7293
|
-
return formatOutput(result2, format, (r) => formatChangesText(r, ctx));
|
|
7294
|
-
}
|
|
7295
7291
|
const DEFAULT_IGNORE = [".analyze/"];
|
|
7296
|
-
|
|
7297
|
-
|
|
7298
|
-
|
|
7299
|
-
|
|
7300
|
-
(f) => !DEFAULT_IGNORE.some((pattern) => f.includes(pattern))
|
|
7301
|
-
);
|
|
7302
|
-
const filesToProcess = options.file ? filesFiltered.filter(
|
|
7303
|
-
(f) => f.toLowerCase().includes(options.file.toLowerCase())
|
|
7304
|
-
) : filesFiltered;
|
|
7305
|
-
const untrackedToProcess = options.file ? untrackedFiltered.filter(
|
|
7306
|
-
(f) => f.toLowerCase().includes(options.file.toLowerCase())
|
|
7307
|
-
) : untrackedFiltered;
|
|
7292
|
+
let parsed = null;
|
|
7293
|
+
if (diffText.trim()) {
|
|
7294
|
+
parsed = parseGitDiff(diffText);
|
|
7295
|
+
}
|
|
7308
7296
|
const fileChanges = [];
|
|
7309
7297
|
let totalAdded = 0;
|
|
7310
7298
|
let totalRemoved = 0;
|
|
7299
|
+
let totalRenames = 0;
|
|
7300
|
+
let totalAddedFiles = 0;
|
|
7301
|
+
let totalDeletedFiles = 0;
|
|
7311
7302
|
const symbolsIndex = await loadCachedSymbolsIndex(cwd);
|
|
7312
|
-
|
|
7313
|
-
const
|
|
7314
|
-
|
|
7315
|
-
|
|
7316
|
-
|
|
7317
|
-
|
|
7318
|
-
|
|
7319
|
-
|
|
7320
|
-
|
|
7321
|
-
|
|
7322
|
-
|
|
7323
|
-
|
|
7324
|
-
|
|
7325
|
-
|
|
7326
|
-
|
|
7327
|
-
|
|
7328
|
-
|
|
7329
|
-
|
|
7303
|
+
if (parsed && parsed.files.length > 0) {
|
|
7304
|
+
for (const file of parsed.files) {
|
|
7305
|
+
const filePath = resolveFilePath(file);
|
|
7306
|
+
if (options.file) {
|
|
7307
|
+
if (!filePath.toLowerCase().includes(options.file.toLowerCase())) continue;
|
|
7308
|
+
}
|
|
7309
|
+
if (DEFAULT_IGNORE.some((p) => filePath.includes(p))) continue;
|
|
7310
|
+
const chunks = extractChunks(file);
|
|
7311
|
+
const { added, removed, entries } = processChunks(chunks, filePath, symbolsIndex);
|
|
7312
|
+
const fileType = resolveFileType(file);
|
|
7313
|
+
const change = {
|
|
7314
|
+
path: filePath,
|
|
7315
|
+
category: detectCategory(filePath),
|
|
7316
|
+
stats: { added, removed },
|
|
7317
|
+
changes: entries,
|
|
7318
|
+
fileType
|
|
7319
|
+
};
|
|
7320
|
+
if (file.type === "RenamedFile") {
|
|
7321
|
+
const renamedFile = file;
|
|
7322
|
+
change.renamed = true;
|
|
7323
|
+
change.renamedFrom = renamedFile.pathBefore;
|
|
7324
|
+
totalRenames++;
|
|
7325
|
+
}
|
|
7326
|
+
if (file.type === "AddedFile") totalAddedFiles++;
|
|
7327
|
+
if (file.type === "DeletedFile") totalDeletedFiles++;
|
|
7328
|
+
totalAdded += added;
|
|
7329
|
+
totalRemoved += removed;
|
|
7330
|
+
fileChanges.push(change);
|
|
7331
|
+
}
|
|
7330
7332
|
}
|
|
7333
|
+
let totalUntrackedLines = 0;
|
|
7334
|
+
const untrackedFiltered = untrackedFiles.filter(
|
|
7335
|
+
(f) => !DEFAULT_IGNORE.some((p) => f.includes(p))
|
|
7336
|
+
);
|
|
7337
|
+
const untrackedToProcess = options.file ? untrackedFiltered.filter((f) => f.toLowerCase().includes(options.file.toLowerCase())) : untrackedFiltered;
|
|
7331
7338
|
for (const filePath of untrackedToProcess) {
|
|
7332
7339
|
const fullFilePath = path.resolve(cwd, filePath);
|
|
7333
7340
|
let lineCount = 0;
|
|
@@ -7349,31 +7356,36 @@ async function changes(options = {}) {
|
|
|
7349
7356
|
category: detectCategory(filePath),
|
|
7350
7357
|
stats: { added: lineCount, removed: 0 },
|
|
7351
7358
|
changes: enrichedEntries,
|
|
7352
|
-
newFile: true
|
|
7359
|
+
newFile: true,
|
|
7360
|
+
fileType: "added"
|
|
7353
7361
|
});
|
|
7354
|
-
|
|
7362
|
+
totalUntrackedLines += lineCount;
|
|
7355
7363
|
} catch {
|
|
7356
7364
|
fileChanges.push({
|
|
7357
7365
|
path: filePath,
|
|
7358
7366
|
category: detectCategory(filePath),
|
|
7359
7367
|
stats: { added: 0, removed: 0 },
|
|
7360
7368
|
changes: [],
|
|
7361
|
-
newFile: true
|
|
7369
|
+
newFile: true,
|
|
7370
|
+
fileType: "added"
|
|
7362
7371
|
});
|
|
7363
7372
|
}
|
|
7364
7373
|
}
|
|
7365
7374
|
const affectedAreas = buildAffectedAreas(fileChanges, cwd);
|
|
7366
|
-
const
|
|
7367
|
-
const totalNewForSummary = options.file ? fileChanges.filter((f) => f.newFile).length : untrackedFiles.length;
|
|
7375
|
+
const trackedFiles = fileChanges.filter((f) => !f.newFile);
|
|
7368
7376
|
const result = {
|
|
7369
7377
|
version: "1.0.0",
|
|
7370
7378
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7371
7379
|
target,
|
|
7372
7380
|
summary: {
|
|
7373
|
-
totalFiles:
|
|
7374
|
-
totalNewFiles:
|
|
7381
|
+
totalFiles: trackedFiles.length,
|
|
7382
|
+
totalNewFiles: untrackedToProcess.length,
|
|
7375
7383
|
totalAdded,
|
|
7376
|
-
totalRemoved
|
|
7384
|
+
totalRemoved,
|
|
7385
|
+
totalUntrackedLines,
|
|
7386
|
+
totalRenames,
|
|
7387
|
+
totalAddedFiles,
|
|
7388
|
+
totalDeletedFiles
|
|
7377
7389
|
},
|
|
7378
7390
|
files: fileChanges,
|
|
7379
7391
|
affectedAreas: affectedAreas.length > 0 ? affectedAreas : void 0
|
|
@@ -7384,6 +7396,142 @@ async function changes(options = {}) {
|
|
|
7384
7396
|
throw new Error(`Erro ao executar changes: ${message}`);
|
|
7385
7397
|
}
|
|
7386
7398
|
}
|
|
7399
|
+
function resolveFilePath(file) {
|
|
7400
|
+
if (file.type === "RenamedFile") return file.pathAfter;
|
|
7401
|
+
return file.path;
|
|
7402
|
+
}
|
|
7403
|
+
function extractChunks(file) {
|
|
7404
|
+
if ("chunks" in file) {
|
|
7405
|
+
return file.chunks.filter((c) => c.type === "Chunk");
|
|
7406
|
+
}
|
|
7407
|
+
return [];
|
|
7408
|
+
}
|
|
7409
|
+
function resolveFileType(file) {
|
|
7410
|
+
switch (file.type) {
|
|
7411
|
+
case "AddedFile":
|
|
7412
|
+
return "added";
|
|
7413
|
+
case "DeletedFile":
|
|
7414
|
+
return "deleted";
|
|
7415
|
+
case "RenamedFile":
|
|
7416
|
+
return "renamed";
|
|
7417
|
+
case "ChangedFile":
|
|
7418
|
+
return "changed";
|
|
7419
|
+
}
|
|
7420
|
+
}
|
|
7421
|
+
function processChunks(chunks, filePath, symbolsIndex) {
|
|
7422
|
+
let added = 0;
|
|
7423
|
+
let removed = 0;
|
|
7424
|
+
const allAddedLines = [];
|
|
7425
|
+
const allDeletedLines = [];
|
|
7426
|
+
for (const chunk of chunks) {
|
|
7427
|
+
for (const change of chunk.changes) {
|
|
7428
|
+
if (change.type === "AddedLine") {
|
|
7429
|
+
added++;
|
|
7430
|
+
allAddedLines.push(change.content);
|
|
7431
|
+
} else if (change.type === "DeletedLine") {
|
|
7432
|
+
removed++;
|
|
7433
|
+
allDeletedLines.push(change.content);
|
|
7434
|
+
}
|
|
7435
|
+
}
|
|
7436
|
+
}
|
|
7437
|
+
const entries = classifyFromStructuredLines(allAddedLines, allDeletedLines);
|
|
7438
|
+
if (entries.length === 0 && added + removed > 0) {
|
|
7439
|
+
const previewText = buildSyntheticDiff(allAddedLines, allDeletedLines);
|
|
7440
|
+
const genericEntries = extractGenericDiffPreview(previewText, filePath);
|
|
7441
|
+
entries.push(...genericEntries);
|
|
7442
|
+
}
|
|
7443
|
+
const enrichedEntries = enrichWithJsDoc(entries, filePath, symbolsIndex);
|
|
7444
|
+
return { added, removed, entries: enrichedEntries };
|
|
7445
|
+
}
|
|
7446
|
+
function buildSyntheticDiff(addedLines, deletedLines) {
|
|
7447
|
+
const lines = [];
|
|
7448
|
+
const maxPreview = 10;
|
|
7449
|
+
for (const line of deletedLines.slice(0, maxPreview)) {
|
|
7450
|
+
lines.push(`-${line}`);
|
|
7451
|
+
}
|
|
7452
|
+
for (const line of addedLines.slice(0, maxPreview)) {
|
|
7453
|
+
lines.push(`+${line}`);
|
|
7454
|
+
}
|
|
7455
|
+
return lines.join("\n");
|
|
7456
|
+
}
|
|
7457
|
+
function classifyFromStructuredLines(addedLines, deletedLines) {
|
|
7458
|
+
const entries = [];
|
|
7459
|
+
const removedSymbols = /* @__PURE__ */ new Map();
|
|
7460
|
+
for (const line of deletedLines) {
|
|
7461
|
+
const multiReexport = extractMultipleReexports(line);
|
|
7462
|
+
if (multiReexport) {
|
|
7463
|
+
for (const name of multiReexport.names) {
|
|
7464
|
+
if (!removedSymbols.has(name)) {
|
|
7465
|
+
removedSymbols.set(name, { kind: multiReexport.kind, content: line });
|
|
7466
|
+
}
|
|
7467
|
+
}
|
|
7468
|
+
continue;
|
|
7469
|
+
}
|
|
7470
|
+
const info = extractSymbolInfo(line);
|
|
7471
|
+
if (info && info.name && isRelevantSymbol(info)) {
|
|
7472
|
+
if (!removedSymbols.has(info.name)) {
|
|
7473
|
+
removedSymbols.set(info.name, { kind: info.kind, content: line });
|
|
7474
|
+
}
|
|
7475
|
+
}
|
|
7476
|
+
}
|
|
7477
|
+
const addedSymbols = /* @__PURE__ */ new Map();
|
|
7478
|
+
for (const line of addedLines) {
|
|
7479
|
+
const multiReexport = extractMultipleReexports(line);
|
|
7480
|
+
if (multiReexport) {
|
|
7481
|
+
for (const name of multiReexport.names) {
|
|
7482
|
+
if (!addedSymbols.has(name)) {
|
|
7483
|
+
addedSymbols.set(name, { kind: multiReexport.kind, content: line });
|
|
7484
|
+
}
|
|
7485
|
+
}
|
|
7486
|
+
continue;
|
|
7487
|
+
}
|
|
7488
|
+
const info = extractSymbolInfo(line);
|
|
7489
|
+
if (info && info.name && isRelevantSymbol(info)) {
|
|
7490
|
+
if (!addedSymbols.has(info.name)) {
|
|
7491
|
+
addedSymbols.set(info.name, { kind: info.kind, content: line });
|
|
7492
|
+
}
|
|
7493
|
+
}
|
|
7494
|
+
}
|
|
7495
|
+
const modifiedNames = /* @__PURE__ */ new Set();
|
|
7496
|
+
for (const name of removedSymbols.keys()) {
|
|
7497
|
+
if (addedSymbols.has(name)) modifiedNames.add(name);
|
|
7498
|
+
}
|
|
7499
|
+
for (const [name, { kind }] of removedSymbols) {
|
|
7500
|
+
if (!modifiedNames.has(name)) {
|
|
7501
|
+
entries.push({ kind, type: "removed", name });
|
|
7502
|
+
}
|
|
7503
|
+
}
|
|
7504
|
+
for (const name of modifiedNames) {
|
|
7505
|
+
const removed = removedSymbols.get(name);
|
|
7506
|
+
const added = addedSymbols.get(name);
|
|
7507
|
+
const detail = generateModifiedDetail(removed.content, added.content, added.kind);
|
|
7508
|
+
entries.push({ kind: added.kind, type: "modified", name, detail });
|
|
7509
|
+
}
|
|
7510
|
+
for (const [name, { kind, content }] of addedSymbols) {
|
|
7511
|
+
if (!modifiedNames.has(name)) {
|
|
7512
|
+
const previewLines = buildPreviewFromLines([content], "added");
|
|
7513
|
+
entries.push({
|
|
7514
|
+
kind,
|
|
7515
|
+
type: "added",
|
|
7516
|
+
name,
|
|
7517
|
+
previewLines: previewLines.length > 0 ? previewLines : void 0
|
|
7518
|
+
});
|
|
7519
|
+
}
|
|
7520
|
+
}
|
|
7521
|
+
return entries;
|
|
7522
|
+
}
|
|
7523
|
+
function buildPreviewFromLines(lines, type) {
|
|
7524
|
+
const preview = [];
|
|
7525
|
+
const limit = type === "added" ? 2 : 4;
|
|
7526
|
+
for (const line of lines) {
|
|
7527
|
+
if (preview.length >= limit) break;
|
|
7528
|
+
const trimmed = line.trim();
|
|
7529
|
+
if (trimmed && !trimmed.startsWith("//") && !trimmed.startsWith("/*") && !/^[})\];,]*$/.test(trimmed)) {
|
|
7530
|
+
preview.push(type === "added" ? `[+] ${line}` : `[+] ${line}`);
|
|
7531
|
+
}
|
|
7532
|
+
}
|
|
7533
|
+
return preview.slice(0, limit);
|
|
7534
|
+
}
|
|
7387
7535
|
function enrichWithJsDoc(entries, filePath, cachedIndex) {
|
|
7388
7536
|
const needsEnrichment = (e) => e.kind !== "import" && e.kind !== "config" && !e.detail;
|
|
7389
7537
|
if (!entries.some(needsEnrichment)) {
|
|
@@ -7496,13 +7644,9 @@ function classifyChanges(diffText) {
|
|
|
7496
7644
|
if (multiReexport) {
|
|
7497
7645
|
for (const name of multiReexport.names) {
|
|
7498
7646
|
if (line.prefix === "remove") {
|
|
7499
|
-
if (!removedSymbols.has(name))
|
|
7500
|
-
removedSymbols.set(name, line);
|
|
7501
|
-
}
|
|
7647
|
+
if (!removedSymbols.has(name)) removedSymbols.set(name, line);
|
|
7502
7648
|
} else {
|
|
7503
|
-
if (!addedSymbols.has(name))
|
|
7504
|
-
addedSymbols.set(name, line);
|
|
7505
|
-
}
|
|
7649
|
+
if (!addedSymbols.has(name)) addedSymbols.set(name, line);
|
|
7506
7650
|
}
|
|
7507
7651
|
}
|
|
7508
7652
|
continue;
|
|
@@ -7510,32 +7654,22 @@ function classifyChanges(diffText) {
|
|
|
7510
7654
|
const info = extractSymbolInfo(line.content);
|
|
7511
7655
|
if (info && info.name && isRelevantSymbol(info)) {
|
|
7512
7656
|
if (line.prefix === "remove") {
|
|
7513
|
-
if (!removedSymbols.has(info.name))
|
|
7514
|
-
removedSymbols.set(info.name, line);
|
|
7515
|
-
}
|
|
7657
|
+
if (!removedSymbols.has(info.name)) removedSymbols.set(info.name, line);
|
|
7516
7658
|
} else {
|
|
7517
|
-
if (!addedSymbols.has(info.name))
|
|
7518
|
-
addedSymbols.set(info.name, line);
|
|
7519
|
-
}
|
|
7659
|
+
if (!addedSymbols.has(info.name)) addedSymbols.set(info.name, line);
|
|
7520
7660
|
}
|
|
7521
7661
|
}
|
|
7522
7662
|
}
|
|
7523
7663
|
const modifiedNames = /* @__PURE__ */ new Set();
|
|
7524
7664
|
for (const name of removedSymbols.keys()) {
|
|
7525
|
-
if (addedSymbols.has(name))
|
|
7526
|
-
modifiedNames.add(name);
|
|
7527
|
-
}
|
|
7665
|
+
if (addedSymbols.has(name)) modifiedNames.add(name);
|
|
7528
7666
|
}
|
|
7529
7667
|
for (const [name, line] of removedSymbols) {
|
|
7530
7668
|
if (!modifiedNames.has(name)) {
|
|
7531
7669
|
const info = extractSymbolInfo(line.content);
|
|
7532
7670
|
if (info) {
|
|
7533
7671
|
processed.add(line.line);
|
|
7534
|
-
entries.push({
|
|
7535
|
-
kind: info.kind,
|
|
7536
|
-
type: "removed",
|
|
7537
|
-
name
|
|
7538
|
-
});
|
|
7672
|
+
entries.push({ kind: info.kind, type: "removed", name });
|
|
7539
7673
|
}
|
|
7540
7674
|
}
|
|
7541
7675
|
}
|
|
@@ -7548,15 +7682,7 @@ function classifyChanges(diffText) {
|
|
|
7548
7682
|
processed.add(removedLine.line);
|
|
7549
7683
|
processed.add(addedLine.line);
|
|
7550
7684
|
const detail = generateModifiedDetail(removedLine.content, addedLine.content, addedInfo.kind);
|
|
7551
|
-
|
|
7552
|
-
const previewLines = extractPreviewLines(diffText, lineNumbers, "modified");
|
|
7553
|
-
entries.push({
|
|
7554
|
-
kind: addedInfo.kind,
|
|
7555
|
-
type: "modified",
|
|
7556
|
-
name,
|
|
7557
|
-
detail,
|
|
7558
|
-
previewLines: previewLines.length > 0 ? previewLines : void 0
|
|
7559
|
-
});
|
|
7685
|
+
entries.push({ kind: addedInfo.kind, type: "modified", name, detail });
|
|
7560
7686
|
}
|
|
7561
7687
|
}
|
|
7562
7688
|
for (const [name, line] of addedSymbols) {
|
|
@@ -7564,13 +7690,7 @@ function classifyChanges(diffText) {
|
|
|
7564
7690
|
const info = extractSymbolInfo(line.content);
|
|
7565
7691
|
if (info) {
|
|
7566
7692
|
processed.add(line.line);
|
|
7567
|
-
|
|
7568
|
-
entries.push({
|
|
7569
|
-
kind: info.kind,
|
|
7570
|
-
type: "added",
|
|
7571
|
-
name,
|
|
7572
|
-
previewLines: previewLines.length > 0 ? previewLines : void 0
|
|
7573
|
-
});
|
|
7693
|
+
entries.push({ kind: info.kind, type: "added", name });
|
|
7574
7694
|
}
|
|
7575
7695
|
}
|
|
7576
7696
|
}
|
|
@@ -7787,52 +7907,6 @@ function extractTypeBody(line) {
|
|
|
7787
7907
|
const eqIndex = line.indexOf("=");
|
|
7788
7908
|
return eqIndex >= 0 ? line.slice(eqIndex + 1).trim() : line.trim();
|
|
7789
7909
|
}
|
|
7790
|
-
var PREVIEW_LINES_LIMIT = 3;
|
|
7791
|
-
function extractPreviewLines(diffText, lineNumbers, type) {
|
|
7792
|
-
if (lineNumbers.length === 0) return [];
|
|
7793
|
-
const lines = diffText.split("\n");
|
|
7794
|
-
const previewLines = [];
|
|
7795
|
-
let foundSymbol = false;
|
|
7796
|
-
for (const targetLine of lineNumbers) {
|
|
7797
|
-
if (previewLines.length >= PREVIEW_LINES_LIMIT) break;
|
|
7798
|
-
const searchStart = Math.max(0, targetLine - 3);
|
|
7799
|
-
const searchEnd = Math.min(lines.length, targetLine + 2);
|
|
7800
|
-
for (let i = searchStart; i < searchEnd; i++) {
|
|
7801
|
-
if (previewLines.length >= PREVIEW_LINES_LIMIT) break;
|
|
7802
|
-
const line = lines[i];
|
|
7803
|
-
if (!line) continue;
|
|
7804
|
-
if (line.startsWith("@@") || line.startsWith("diff ") || line.startsWith("index ")) {
|
|
7805
|
-
continue;
|
|
7806
|
-
}
|
|
7807
|
-
const isAdded = line.startsWith("+");
|
|
7808
|
-
const isRemoved = line.startsWith("-");
|
|
7809
|
-
if (type === "added" && isAdded) {
|
|
7810
|
-
const content = line.slice(1);
|
|
7811
|
-
const trimmed = content.trim();
|
|
7812
|
-
if (trimmed && !trimmed.startsWith("//") && !trimmed.startsWith("/*") && !/^[})\];,\s]*$/.test(trimmed)) {
|
|
7813
|
-
previewLines.push(`[+] ${content}`);
|
|
7814
|
-
foundSymbol = true;
|
|
7815
|
-
}
|
|
7816
|
-
} else if (type === "modified") {
|
|
7817
|
-
if (isRemoved) {
|
|
7818
|
-
const content = line.slice(1);
|
|
7819
|
-
const trimmed = content.trim();
|
|
7820
|
-
if (trimmed && !trimmed.startsWith("//") && !trimmed.startsWith("/*") && !/^[})\];,\s]*$/.test(trimmed)) {
|
|
7821
|
-
previewLines.push(`[-] ${content}`);
|
|
7822
|
-
}
|
|
7823
|
-
} else if (isAdded) {
|
|
7824
|
-
const content = line.slice(1);
|
|
7825
|
-
const trimmed = content.trim();
|
|
7826
|
-
if (trimmed && !trimmed.startsWith("//") && !trimmed.startsWith("/*") && !/^[})\];,\s]*$/.test(trimmed)) {
|
|
7827
|
-
previewLines.push(`[+] ${content}`);
|
|
7828
|
-
}
|
|
7829
|
-
}
|
|
7830
|
-
}
|
|
7831
|
-
}
|
|
7832
|
-
if (foundSymbol && type === "added") break;
|
|
7833
|
-
}
|
|
7834
|
-
return previewLines.slice(0, PREVIEW_LINES_LIMIT);
|
|
7835
|
-
}
|
|
7836
7910
|
var GENERIC_PREVIEW_LINES_LIMIT = 5;
|
|
7837
7911
|
function extractGenericDiffPreview(diffText, filePath) {
|
|
7838
7912
|
if (!diffText.trim()) return [];
|
package/dist/cli.js
CHANGED
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
depsInfo,
|
|
5
5
|
depsSearch,
|
|
6
6
|
describe
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-4AFO5NLB.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-
|
|
23
|
+
} from "./chunk-WESIQAV2.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-
|
|
134
|
+
const { startMcpServer } = await import("./server-XCWCN2RZ.js");
|
|
135
135
|
await startMcpServer();
|
|
136
136
|
return;
|
|
137
137
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -400,6 +400,12 @@ interface FileChange {
|
|
|
400
400
|
changes: ChangeEntry[];
|
|
401
401
|
/** Arquivo untracked (nunca commitado) */
|
|
402
402
|
newFile?: boolean;
|
|
403
|
+
/** Arquivo foi renomeado */
|
|
404
|
+
renamed?: boolean;
|
|
405
|
+
/** Path original antes do rename */
|
|
406
|
+
renamedFrom?: string;
|
|
407
|
+
/** Tipo de mudança do arquivo no git */
|
|
408
|
+
fileType?: "added" | "deleted" | "changed" | "renamed";
|
|
403
409
|
}
|
|
404
410
|
interface ChangesOptions extends CommandOptions {
|
|
405
411
|
target?: "staged" | "unstaged" | "all";
|
|
@@ -421,6 +427,14 @@ interface ChangesResult {
|
|
|
421
427
|
totalNewFiles: number;
|
|
422
428
|
totalAdded: number;
|
|
423
429
|
totalRemoved: number;
|
|
430
|
+
/** Linhas de arquivos untracked (separado do total de tracked files) */
|
|
431
|
+
totalUntrackedLines: number;
|
|
432
|
+
/** Quantidade de arquivos renomeados */
|
|
433
|
+
totalRenames: number;
|
|
434
|
+
/** Arquivos completamente novos (added no git) */
|
|
435
|
+
totalAddedFiles: number;
|
|
436
|
+
/** Arquivos completamente deletados */
|
|
437
|
+
totalDeletedFiles: number;
|
|
424
438
|
};
|
|
425
439
|
files: FileChange[];
|
|
426
440
|
affectedAreas?: AffectedArea[];
|
|
@@ -625,9 +639,10 @@ declare function functions(options?: FunctionsOptions): Promise<string>;
|
|
|
625
639
|
/**
|
|
626
640
|
* Comando CHANGES - Resumo semantico de mudancas git
|
|
627
641
|
*
|
|
628
|
-
* Analisa arquivos modificados via git diff
|
|
629
|
-
* (added/modified/removed) e categoria
|
|
630
|
-
* usando pattern matching deterministico,
|
|
642
|
+
* Analisa arquivos modificados via git diff usando parse-git-diff como parser,
|
|
643
|
+
* classifica mudancas por tipo (added/modified/removed) e categoria
|
|
644
|
+
* (function/type/import/const/component/hook) usando pattern matching deterministico,
|
|
645
|
+
* e retorna um resumo estruturado.
|
|
631
646
|
*/
|
|
632
647
|
|
|
633
648
|
/**
|
|
@@ -635,6 +650,7 @@ declare function functions(options?: FunctionsOptions): Promise<string>;
|
|
|
635
650
|
*
|
|
636
651
|
* Retorna um resumo semantico de mudancas git otimizado para consumo de IA.
|
|
637
652
|
* Ao inves de mostrar diff bruto, classifica mudancas por tipo e categoria.
|
|
653
|
+
* Usa parse-git-diff como parser principal para maior confiabilidade.
|
|
638
654
|
*/
|
|
639
655
|
declare function changes(options?: ChangesOptions): Promise<string>;
|
|
640
656
|
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
depsInfo,
|
|
4
4
|
depsSearch,
|
|
5
5
|
describe
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-4AFO5NLB.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-
|
|
22
|
+
} from "./chunk-WESIQAV2.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.22.
|
|
3
|
+
"version": "3.22.2",
|
|
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",
|
|
@@ -46,6 +46,7 @@
|
|
|
46
46
|
"@modelcontextprotocol/sdk": "^1.25.3",
|
|
47
47
|
"knip": "^5.44.0",
|
|
48
48
|
"minimatch": "^10.0.1",
|
|
49
|
+
"parse-git-diff": "^0.0.20",
|
|
49
50
|
"skott": "^0.35.8",
|
|
50
51
|
"ts-morph": "^27.0.2",
|
|
51
52
|
"zod": "^3.25.76"
|