@justmpm/ai-tool 3.19.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-GBNBYBLN.js";
23
+ } from "./chunk-MEG5Q7XP.js";
24
24
 
25
25
  // src/commands/describe.ts
26
26
  var STOPWORDS = /* @__PURE__ */ new Set([
@@ -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):
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 += `
1898
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}): `;
@@ -5187,6 +5235,20 @@ function getDiffArgs(target) {
5187
5235
  return ["HEAD"];
5188
5236
  }
5189
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
+ }
5190
5252
  function getChangedFiles(target, cwd) {
5191
5253
  if (!hasGitRepo(cwd)) return [];
5192
5254
  try {
@@ -7151,6 +7213,8 @@ function getTriggerIcon(trigger) {
7151
7213
 
7152
7214
  // src/commands/changes.ts
7153
7215
  import * as path from "path";
7216
+ import { readFileSync as readFileSync7 } from "fs";
7217
+ var UNTRACKED_PREVIEW_LINES = 20;
7154
7218
  async function changes(options = {}) {
7155
7219
  const { cwd, format } = parseCommandOptions(options);
7156
7220
  const ctx = options.ctx || "cli";
@@ -7160,13 +7224,15 @@ async function changes(options = {}) {
7160
7224
  }
7161
7225
  try {
7162
7226
  const changedFiles = getChangedFiles(target, cwd);
7163
- if (changedFiles.length === 0) {
7227
+ const untrackedFiles = getUntrackedFiles(cwd);
7228
+ if (changedFiles.length === 0 && untrackedFiles.length === 0) {
7164
7229
  const result2 = {
7165
7230
  version: "1.0.0",
7166
7231
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
7167
7232
  target,
7168
7233
  summary: {
7169
7234
  totalFiles: 0,
7235
+ totalNewFiles: 0,
7170
7236
  totalAdded: 0,
7171
7237
  totalRemoved: 0
7172
7238
  },
@@ -7178,9 +7244,15 @@ async function changes(options = {}) {
7178
7244
  const filesFiltered = changedFiles.filter(
7179
7245
  (f) => !DEFAULT_IGNORE.some((pattern) => f.includes(pattern))
7180
7246
  );
7247
+ const untrackedFiltered = untrackedFiles.filter(
7248
+ (f) => !DEFAULT_IGNORE.some((pattern) => f.includes(pattern))
7249
+ );
7181
7250
  const filesToProcess = options.file ? filesFiltered.filter(
7182
7251
  (f) => f.toLowerCase().includes(options.file.toLowerCase())
7183
7252
  ) : filesFiltered;
7253
+ const untrackedToProcess = options.file ? untrackedFiltered.filter(
7254
+ (f) => f.toLowerCase().includes(options.file.toLowerCase())
7255
+ ) : untrackedFiltered;
7184
7256
  const fileChanges = [];
7185
7257
  let totalAdded = 0;
7186
7258
  let totalRemoved = 0;
@@ -7207,14 +7279,50 @@ async function changes(options = {}) {
7207
7279
  changes: enrichedEntries
7208
7280
  });
7209
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
+ }
7210
7316
  const affectedAreas = buildAffectedAreas(fileChanges, cwd);
7211
7317
  const totalForSummary = options.file ? fileChanges.length : changedFiles.length;
7318
+ const totalNewForSummary = options.file ? fileChanges.filter((f) => f.newFile).length : untrackedFiles.length;
7212
7319
  const result = {
7213
7320
  version: "1.0.0",
7214
7321
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
7215
7322
  target,
7216
7323
  summary: {
7217
7324
  totalFiles: totalForSummary,
7325
+ totalNewFiles: totalNewForSummary,
7218
7326
  totalAdded,
7219
7327
  totalRemoved
7220
7328
  },
@@ -7710,7 +7818,7 @@ function extractGenericDiffPreview(diffText, filePath) {
7710
7818
  }
7711
7819
 
7712
7820
  // src/commands/find.ts
7713
- import { existsSync as existsSync10, readFileSync as readFileSync7 } from "fs";
7821
+ import { existsSync as existsSync10, readFileSync as readFileSync8 } from "fs";
7714
7822
  import { join as join11 } from "path";
7715
7823
 
7716
7824
  // src/cache/gitHistory.ts
@@ -7910,7 +8018,7 @@ function searchInIndex(index, query, filterType, allowedFiles, cwd) {
7910
8018
  if (!existsSync10(fullPath)) {
7911
8019
  continue;
7912
8020
  }
7913
- const content = readFileSync7(fullPath, "utf-8");
8021
+ const content = readFileSync8(fullPath, "utf-8");
7914
8022
  const lines = content.split("\n");
7915
8023
  usageFilesScanned++;
7916
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-XA37DX5M.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-GBNBYBLN.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-O6CBWSYZ.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-GBNBYBLN.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-XA37DX5M.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-GBNBYBLN.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.19.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",