@archznn/xavva 3.1.2 → 3.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.
Files changed (80) hide show
  1. package/README.md +221 -12
  2. package/package.json +3 -2
  3. package/src/commands/AuditCommand.ts +12 -10
  4. package/src/commands/BuildCommand.ts +9 -7
  5. package/src/commands/ChangelogCommand.ts +5 -5
  6. package/src/commands/CleanCommand.ts +242 -0
  7. package/src/commands/CompletionCommand.ts +7 -7
  8. package/src/commands/DbCommand.ts +43 -14
  9. package/src/commands/DeployCommand.ts +252 -229
  10. package/src/commands/DepsCommand.ts +174 -174
  11. package/src/commands/DockerCommand.ts +35 -4
  12. package/src/commands/DoctorCommand.ts +252 -239
  13. package/src/commands/EncodingCommand.ts +26 -19
  14. package/src/commands/HealthCommand.ts +7 -7
  15. package/src/commands/HelpCommand.ts +34 -14
  16. package/src/commands/HistoryCommand.ts +5 -5
  17. package/src/commands/HttpCommand.ts +27 -1
  18. package/src/commands/IdeCommand.ts +313 -0
  19. package/src/commands/InitCommand.ts +26 -25
  20. package/src/commands/LogsCommand.ts +8 -6
  21. package/src/commands/ProfilesCommand.ts +6 -6
  22. package/src/commands/RedoCommand.ts +2 -2
  23. package/src/commands/RunCommand.ts +64 -24
  24. package/src/commands/StartCommand.ts +9 -7
  25. package/src/commands/TestCommand.ts +25 -1
  26. package/src/commands/TomcatCommand.ts +232 -88
  27. package/src/config/versions.ts +111 -9
  28. package/src/di/container.ts +239 -105
  29. package/src/errors/ErrorHandler.ts +23 -19
  30. package/src/errors/errorMessages.ts +235 -0
  31. package/src/index.ts +20 -6
  32. package/src/logging/FileLogger.ts +235 -0
  33. package/src/logging/Logger.ts +545 -0
  34. package/src/logging/OperationLogger.ts +296 -0
  35. package/src/logging/ProgressLogger.ts +187 -0
  36. package/src/logging/TableLogger.ts +246 -0
  37. package/src/logging/colors.ts +167 -0
  38. package/src/logging/constants.ts +176 -0
  39. package/src/logging/formatters.ts +337 -0
  40. package/src/logging/index.ts +93 -0
  41. package/src/logging/types.ts +64 -0
  42. package/src/plugins/PluginManager.ts +325 -0
  43. package/src/plugins/types.ts +82 -0
  44. package/src/services/AuditService.ts +5 -3
  45. package/src/services/BuildService.ts +15 -17
  46. package/src/services/DashboardService.ts +14 -3
  47. package/src/services/DbService.ts +35 -34
  48. package/src/services/DependencyAnalyzerService.ts +18 -18
  49. package/src/services/DependencyCacheService.ts +303 -0
  50. package/src/services/DeployWatcher.ts +127 -23
  51. package/src/services/DockerService.ts +3 -3
  52. package/src/services/EmbeddedTomcatService.ts +13 -12
  53. package/src/services/FileWatcher.ts +15 -7
  54. package/src/services/HttpService.ts +5 -5
  55. package/src/services/LogAnalyzer.ts +26 -22
  56. package/src/services/PerformanceProfiler.ts +267 -0
  57. package/src/services/ProjectService.ts +3 -0
  58. package/src/services/TestService.ts +3 -3
  59. package/src/services/TomcatService.ts +46 -25
  60. package/src/services/tomcat/TomcatBackupManager.ts +330 -0
  61. package/src/services/tomcat/TomcatChecksumVerifier.ts +211 -0
  62. package/src/services/tomcat/TomcatCompatibilityChecker.ts +298 -0
  63. package/src/services/tomcat/TomcatDownloadCache.ts +250 -0
  64. package/src/services/tomcat/TomcatDownloadService.ts +335 -0
  65. package/src/services/tomcat/TomcatInstallerService.ts +474 -0
  66. package/src/services/tomcat/TomcatMirrorManager.ts +181 -0
  67. package/src/services/tomcat/index.ts +36 -0
  68. package/src/services/tomcat/types.ts +120 -0
  69. package/src/types/args.ts +68 -1
  70. package/src/types/configSchema.ts +174 -0
  71. package/src/utils/ChangelogGenerator.ts +11 -11
  72. package/src/utils/LoggerLevel.ts +44 -20
  73. package/src/utils/ProgressBar.ts +87 -46
  74. package/src/utils/argsParser.ts +260 -0
  75. package/src/utils/config.ts +340 -189
  76. package/src/utils/constants.ts +87 -9
  77. package/src/utils/dryRun.ts +192 -0
  78. package/src/utils/processManager.ts +23 -7
  79. package/src/utils/security.ts +293 -0
  80. package/src/utils/ui.ts +299 -428
@@ -1,13 +1,26 @@
1
1
  /**
2
2
  * DeployWatcher - Específico para watch de deploy
3
- * Usa FileWatcher genérico e adiciona lógica de deploy
3
+ *
4
+ * Melhorias:
5
+ * - Debounce inteligente com batch processing
6
+ * - Priorização de tipos de arquivos
7
+ * - Rate limiting de builds
8
+ * - Métricas de performance
4
9
  */
5
10
 
6
11
  import { FileWatcher, type FileChangeEvent } from "./FileWatcher";
7
12
  import { DeployCommand } from "../commands/DeployCommand";
8
- import { Logger } from "../utils/ui";
13
+ import { Logger } from "../logging";
9
14
  import type { AppConfig } from "../types/config";
10
- import { WATCHER_DEBOUNCE_MS, WATCHER_COOLING_MS } from "../utils/constants";
15
+ import { TIMEOUTS } from "../config/versions";
16
+
17
+ interface WatcherMetrics {
18
+ filesChanged: number;
19
+ buildsTriggered: number;
20
+ lastBuildTime: number;
21
+ avgBuildTime: number;
22
+ buildTimes: number[];
23
+ }
11
24
 
12
25
  export class DeployWatcher {
13
26
  private fileWatcher: FileWatcher;
@@ -16,6 +29,29 @@ export class DeployWatcher {
16
29
  private modifiedFiles = new Set<string>();
17
30
  private pendingFiles = new Set<string>();
18
31
  private hasPendingChanges = false;
32
+ private logger = Logger.getInstance();
33
+
34
+ // Debounce e batching
35
+ private debounceTimer: ReturnType<typeof setTimeout> | null = null;
36
+ private readonly DEBOUNCE_MS = TIMEOUTS.DEBOUNCE;
37
+ private readonly MAX_BATCH_SIZE = 50;
38
+ private readonly MIN_BUILD_INTERVAL_MS = 500;
39
+
40
+ // Métricas
41
+ private metrics: WatcherMetrics = {
42
+ filesChanged: 0,
43
+ buildsTriggered: 0,
44
+ lastBuildTime: 0,
45
+ avgBuildTime: 0,
46
+ buildTimes: [],
47
+ };
48
+
49
+ // Priorização de arquivos
50
+ private static readonly PRIORITY = {
51
+ BUILD_CONFIG: 1, // pom.xml, build.gradle
52
+ JAVA: 2, // .java
53
+ RESOURCE: 3, // .jsp, .html, etc
54
+ };
19
55
 
20
56
  constructor(
21
57
  private config: AppConfig,
@@ -23,8 +59,8 @@ export class DeployWatcher {
23
59
  ) {
24
60
  this.fileWatcher = new FileWatcher({
25
61
  recursive: true,
26
- debounceMs: WATCHER_DEBOUNCE_MS,
27
- coolingMs: WATCHER_COOLING_MS,
62
+ debounceMs: TIMEOUTS.WATCHER_DEBOUNCE,
63
+ coolingMs: TIMEOUTS.COOLING,
28
64
  });
29
65
  }
30
66
 
@@ -41,7 +77,7 @@ export class DeployWatcher {
41
77
  // Inicia o watcher
42
78
  this.fileWatcher.start();
43
79
 
44
- Logger.info("DeployWatcher", "Monitorando alterações...");
80
+ this.logger.status("watch", "running", "monitorando arquivos");
45
81
  }
46
82
 
47
83
  /**
@@ -77,7 +113,8 @@ export class DeployWatcher {
77
113
  private async handleBuildConfigChange(event: FileChangeEvent): Promise<void> {
78
114
  if (!event.filename) return;
79
115
 
80
- Logger.watcher(`Build configuration changed: ${event.filename}`, 'warn');
116
+ this.logger.file(event.filename, 'changed');
117
+ this.logger.info("Configuração de build alterada - rebuild completo necessário");
81
118
 
82
119
  // Limpa cache quando config muda
83
120
  const { BuildCacheService } = await import("./BuildCacheService");
@@ -87,22 +124,57 @@ export class DeployWatcher {
87
124
  }
88
125
 
89
126
  /**
90
- * Trata mudança em arquivo Java
127
+ * Trata mudança em arquivo Java com debounce inteligente
91
128
  */
92
129
  private handleJavaChange(event: FileChangeEvent): void {
93
- if (!event.filename || this.isDeploying) {
94
- if (event.filename) {
95
- this.pendingFiles.add(event.filename);
96
- this.hasPendingChanges = true;
97
- }
130
+ if (!event.filename) return;
131
+
132
+ this.metrics.filesChanged++;
133
+ this.logger.file(event.filename, 'changed');
134
+ this.modifiedFiles.add(event.filename);
135
+
136
+ // Se muitos arquivos mudaram, faz full build
137
+ if (this.modifiedFiles.size >= this.MAX_BATCH_SIZE) {
138
+ this.logger.warn(`Muitos arquivos modificados (${this.modifiedFiles.size}) - forçando build completo`);
139
+ this.pendingFullBuild = true;
140
+ this.flush();
98
141
  return;
99
142
  }
100
143
 
101
- Logger.watcher(event.filename, 'watch');
102
- this.modifiedFiles.add(event.filename);
144
+ // Debounce normal
145
+ if (this.debounceTimer) {
146
+ clearTimeout(this.debounceTimer);
147
+ }
148
+
149
+ this.debounceTimer = setTimeout(() => {
150
+ this.flush();
151
+ }, this.DEBOUNCE_MS);
152
+ }
153
+
154
+ /**
155
+ * Processa batch de arquivos modificados
156
+ */
157
+ private flush(): void {
158
+ if (this.debounceTimer) {
159
+ clearTimeout(this.debounceTimer);
160
+ this.debounceTimer = null;
161
+ }
162
+
163
+ const files = [...this.modifiedFiles];
164
+ this.modifiedFiles.clear();
103
165
 
104
- // Debounce para acumular múltiplas mudanças
105
- this.scheduleDeploy();
166
+ if (files.length === 0) return;
167
+
168
+ // Rate limiting
169
+ const timeSinceLastBuild = Date.now() - this.metrics.lastBuildTime;
170
+ if (timeSinceLastBuild < this.MIN_BUILD_INTERVAL_MS) {
171
+ const delay = this.MIN_BUILD_INTERVAL_MS - timeSinceLastBuild;
172
+ setTimeout(() => this.run(this.pendingFullBuild ? false : true, files), delay);
173
+ } else {
174
+ this.run(this.pendingFullBuild ? false : true, files);
175
+ }
176
+
177
+ this.pendingFullBuild = false;
106
178
  }
107
179
 
108
180
  /**
@@ -111,12 +183,12 @@ export class DeployWatcher {
111
183
  private async handleResourceChange(event: FileChangeEvent): Promise<void> {
112
184
  if (!event.filename) return;
113
185
 
114
- Logger.watcher(event.filename, 'resource');
186
+ this.logger.file(event.filename, 'changed');
115
187
 
116
188
  try {
117
189
  await this.deployCmd.syncResource(this.config, event.filename);
118
190
  } catch (error) {
119
- Logger.error(`Falha ao sincronizar recurso: ${event.filename}`);
191
+ this.logger.error(`Falha ao sincronizar: ${event.filename}`);
120
192
  }
121
193
  }
122
194
 
@@ -134,12 +206,21 @@ export class DeployWatcher {
134
206
  }
135
207
 
136
208
  /**
137
- * Executa o deploy
209
+ * Executa o deploy com métricas
138
210
  */
139
211
  private async run(incremental = false, changedFiles?: string[]): Promise<void> {
140
- if (this.isDeploying) return;
212
+ if (this.isDeploying) {
213
+ // Acumula para próximo ciclo
214
+ if (changedFiles) {
215
+ changedFiles.forEach(f => this.pendingFiles.add(f));
216
+ this.hasPendingChanges = true;
217
+ }
218
+ return;
219
+ }
141
220
 
142
221
  this.isDeploying = true;
222
+ const buildStart = performance.now();
223
+ this.metrics.buildsTriggered++;
143
224
 
144
225
  try {
145
226
  await this.deployCmd.execute(this.config, {
@@ -147,18 +228,34 @@ export class DeployWatcher {
147
228
  incremental,
148
229
  changedFiles,
149
230
  });
231
+
232
+ // Atualiza métricas
233
+ const buildTime = performance.now() - buildStart;
234
+ this.metrics.lastBuildTime = Date.now();
235
+ this.metrics.buildTimes.push(buildTime);
236
+
237
+ // Mantém apenas últimos 10 builds para média
238
+ if (this.metrics.buildTimes.length > 10) {
239
+ this.metrics.buildTimes.shift();
240
+ }
241
+
242
+ this.metrics.avgBuildTime =
243
+ this.metrics.buildTimes.reduce((a, b) => a + b, 0) / this.metrics.buildTimes.length;
244
+
245
+ this.logger.debug(`Build em ${buildTime.toFixed(0)}ms (média: ${this.metrics.avgBuildTime.toFixed(0)}ms)`);
246
+
150
247
  } catch (error) {
151
248
  // Erro já é tratado pelo comando
152
249
  } finally {
153
250
  this.isDeploying = false;
154
251
 
155
252
  // Processa mudanças pendentes
156
- if (this.hasPendingChanges) {
253
+ if (this.hasPendingChanges || this.pendingFiles.size > 0) {
157
254
  const pending = [...this.pendingFiles];
158
255
  this.pendingFiles.clear();
159
256
  this.hasPendingChanges = false;
160
257
 
161
- Logger.watcher(`Processing ${pending.length} pending change(s)...`, 'warn');
258
+ this.logger.info(`${pending.length} arquivo(s) pendente(s)`);
162
259
 
163
260
  setTimeout(() => {
164
261
  this.run(true, pending);
@@ -167,6 +264,13 @@ export class DeployWatcher {
167
264
  }
168
265
  }
169
266
 
267
+ /**
268
+ * Obtém métricas do watcher
269
+ */
270
+ getMetrics(): WatcherMetrics {
271
+ return { ...this.metrics };
272
+ }
273
+
170
274
  /**
171
275
  * Verifica se é arquivo de recurso (não Java)
172
276
  */
@@ -3,7 +3,7 @@
3
3
  * Gera configs e gerencia containers
4
4
  */
5
5
 
6
- import { Logger } from "../utils/ui";
6
+ import { Logger, C } from "../utils/ui";
7
7
  import { spawn } from "child_process";
8
8
  import fs from "fs";
9
9
  import path from "path";
@@ -291,8 +291,8 @@ services:
291
291
 
292
292
  Logger.divider();
293
293
  for (const c of containers) {
294
- const statusColor = c.status.includes("Up") ? Logger.C.success : Logger.C.error;
295
- Logger.info(c.name, `${statusColor}${c.status}${Logger.C.reset}`);
294
+ const statusColor = c.status.includes("Up") ? C.success : C.error;
295
+ Logger.info(c.name, `${statusColor}${c.status}${C.reset}`);
296
296
  if (c.ports) {
297
297
  Logger.dim(` ${c.ports}`);
298
298
  }
@@ -1,4 +1,4 @@
1
- import { Logger } from "../utils/ui";
1
+ import { Logger } from "../logging";
2
2
  import { ProgressBar, ThemedSpinner } from "../utils/ProgressBar";
3
3
  import { VERSIONS, getAvailableTomcatVersions, isSupportedTomcatVersion } from "../config/versions";
4
4
  import {
@@ -46,6 +46,7 @@ export class EmbeddedTomcatService {
46
46
  private tomcatHome: string;
47
47
  private downloadUrl: string;
48
48
  private isInstalled: boolean = false;
49
+ private logger = Logger.getInstance();
49
50
 
50
51
  // Versões agora centralizadas em src/config/versions.ts
51
52
 
@@ -110,13 +111,13 @@ export class EmbeddedTomcatService {
110
111
  */
111
112
  async install(): Promise<boolean> {
112
113
  if (this.checkInstallation()) {
113
- Logger.info("Tomcat", `Versão ${this.version} já instalada`);
114
+ this.logger.info(`Tomcat: Versão ${this.version} já instalada`);
114
115
  return true;
115
116
  }
116
117
 
117
- Logger.section("Instalando Tomcat Embutido");
118
- Logger.info("Versão", this.version);
119
- Logger.info("Destino", this.tomcatHome);
118
+ this.logger.section("Instalando Tomcat Embutido");
119
+ this.logger.info(`Versão: ${this.version}`);
120
+ this.logger.info(`Destino: ${this.tomcatHome}`);
120
121
 
121
122
  // Cria diretório base
122
123
  if (!existsSync(this.baseDir)) {
@@ -152,10 +153,10 @@ export class EmbeddedTomcatService {
152
153
  await this.configureContextXml();
153
154
 
154
155
  this.isInstalled = true;
155
- Logger.success(`Tomcat ${this.version} instalado com sucesso!`);
156
+ this.logger.success(`Tomcat ${this.version} instalado com sucesso!`);
156
157
  return true;
157
158
  } catch (error) {
158
- Logger.error(`Falha ao instalar Tomcat: ${error}`);
159
+ this.logger.error(`Falha ao instalar Tomcat: ${error}`);
159
160
  // Limpa arquivos parciais
160
161
  if (existsSync(this.tomcatHome)) {
161
162
  await fsPromises.rm(this.tomcatHome, { recursive: true, force: true });
@@ -203,7 +204,7 @@ export class EmbeddedTomcatService {
203
204
  );
204
205
 
205
206
  await fsPromises.writeFile(serverXmlPath, content, "utf-8");
206
- Logger.debug(`server.xml configurado na porta ${this.port}`);
207
+ this.logger.debug(`server.xml configurado na porta ${this.port}`);
207
208
  }
208
209
 
209
210
  /**
@@ -280,7 +281,7 @@ export class EmbeddedTomcatService {
280
281
  </Context>`;
281
282
 
282
283
  writeFileSync(contextFile, content);
283
- Logger.debug(`Context criado: ${contextFile}`);
284
+ this.logger.debug(`Context criado: ${contextFile}`);
284
285
  }
285
286
 
286
287
  /**
@@ -394,7 +395,7 @@ export class EmbeddedTomcatService {
394
395
  await fsPromises.writeFile(destPath, allChunks);
395
396
 
396
397
  const sizeMB = (received / 1024 / 1024).toFixed(1);
397
- Logger.info("Download", `${sizeMB} MB baixados`);
398
+ this.logger.info(`Download: ${sizeMB} MB baixados`);
398
399
  } else {
399
400
  // Sem content-length, usar spinner temático
400
401
  const spinner = new ThemedSpinner();
@@ -406,7 +407,7 @@ export class EmbeddedTomcatService {
406
407
  stop(true);
407
408
 
408
409
  const sizeMB = (buffer.byteLength / 1024 / 1024).toFixed(1);
409
- Logger.info("Download", `${sizeMB} MB baixados`);
410
+ this.logger.info(`Download: ${sizeMB} MB baixados`);
410
411
  } catch (error) {
411
412
  stop(false);
412
413
  throw error;
@@ -455,7 +456,7 @@ export class EmbeddedTomcatService {
455
456
  async uninstall(): Promise<void> {
456
457
  if (existsSync(this.tomcatHome)) {
457
458
  await fsPromises.rm(this.tomcatHome, { recursive: true, force: true });
458
- Logger.info("Tomcat", `Versão ${this.version} removida`);
459
+ this.logger.info(`Tomcat: Versão ${this.version} removida`);
459
460
  }
460
461
  }
461
462
 
@@ -5,7 +5,7 @@
5
5
  */
6
6
 
7
7
  import { watch, type FSWatcher } from "fs";
8
- import { Logger } from "../utils/ui";
8
+ import { Logger } from "../logging";
9
9
 
10
10
  export interface FileWatcherOptions {
11
11
  recursive?: boolean;
@@ -29,6 +29,7 @@ export class FileWatcher {
29
29
  private debounceTimers: Map<string, Timer> = new Map();
30
30
  private coolingFiles: Set<string> = new Set();
31
31
  private isWatching = false;
32
+ private logger = Logger.getInstance();
32
33
 
33
34
  private static readonly DEFAULT_OPTIONS: Required<FileWatcherOptions> = {
34
35
  recursive: true,
@@ -74,7 +75,7 @@ export class FileWatcher {
74
75
  */
75
76
  start(rootPath: string = process.cwd()): void {
76
77
  if (this.isWatching) {
77
- Logger.debug("FileWatcher está rodando");
78
+ // Silently ignore
78
79
  return;
79
80
  }
80
81
 
@@ -85,7 +86,7 @@ export class FileWatcher {
85
86
  );
86
87
 
87
88
  this.isWatching = true;
88
- Logger.debug(`FileWatcher iniciado em ${rootPath}`);
89
+ // Started silently
89
90
  }
90
91
 
91
92
  /**
@@ -102,7 +103,7 @@ export class FileWatcher {
102
103
  this.debounceTimers.clear();
103
104
 
104
105
  this.isWatching = false;
105
- Logger.debug("FileWatcher parado");
106
+ // Stopped silently
106
107
  }
107
108
 
108
109
  /**
@@ -190,11 +191,11 @@ export class FileWatcher {
190
191
  const result = handler(event);
191
192
  if (result instanceof Promise) {
192
193
  result.catch(err => {
193
- Logger.debug(`Erro em handler de watch: ${err.message}`);
194
+ this.logger.debug(`Erro em handler de watch: ${err.message}`);
194
195
  });
195
196
  }
196
197
  } catch (err) {
197
- Logger.debug(`Erro em handler de watch: ${(err as Error).message}`);
198
+ this.logger.debug(`Erro em handler de watch: ${(err as Error).message}`);
198
199
  }
199
200
  }
200
201
  }
@@ -208,7 +209,14 @@ export class FileWatcher {
208
209
  if (pattern === "*") return true;
209
210
 
210
211
  try {
211
- const regex = new RegExp(pattern);
212
+ // Quando um RegExp é convertido para string (ex: usado como chave de Map),
213
+ // ele vira algo como "/\\.java$/". Precisamos extrair o padrão real.
214
+ let patternStr = pattern;
215
+ if (pattern.length > 2 && pattern.startsWith("/") && pattern.lastIndexOf("/") > 0) {
216
+ const lastSlash = pattern.lastIndexOf("/");
217
+ patternStr = pattern.slice(1, lastSlash);
218
+ }
219
+ const regex = new RegExp(patternStr);
212
220
  return regex.test(filename);
213
221
  } catch {
214
222
  // Se não for regex válido, trata como string simples
@@ -3,7 +3,7 @@
3
3
  * Similar ao Postman/curl mas integrado com o projeto
4
4
  */
5
5
 
6
- import { Logger } from "../utils/ui";
6
+ import { Logger, C } from "../utils/ui";
7
7
  import type { ApiEndpoint } from "../types/endpoint";
8
8
 
9
9
  export interface HttpRequest {
@@ -195,12 +195,12 @@ export class HttpService {
195
195
  }
196
196
 
197
197
  private printResponse(res: HttpResponse): void {
198
- const statusColor = res.status < 300 ? Logger.C.success
199
- : res.status < 400 ? Logger.C.warning
200
- : Logger.C.error;
198
+ const statusColor = res.status < 300 ? C.success
199
+ : res.status < 400 ? C.warning
200
+ : C.error;
201
201
 
202
202
  Logger.divider();
203
- Logger.info("Status", `${statusColor}${res.status} ${res.statusText}${Logger.C.reset}`);
203
+ Logger.info("Status", `${statusColor}${res.status} ${res.statusText}${C.reset}`);
204
204
  Logger.info("Duration", `${res.duration}ms`);
205
205
  Logger.info("Size", `${this.formatBytes(res.size)}`);
206
206
 
@@ -1,8 +1,9 @@
1
- import { Logger } from "../utils/ui";
1
+ import { Logger, Colors } from "../logging";
2
2
  import type { ProjectConfig } from "../types/config";
3
3
 
4
4
  export class LogAnalyzer {
5
5
  private projectPrefixes: string[] = [];
6
+ private logger = Logger.getInstance();
6
7
 
7
8
  constructor(private config: ProjectConfig) {
8
9
  // Tentamos inferir prefixos comuns do projeto.
@@ -20,18 +21,18 @@ export class LogAnalyzer {
20
21
  }
21
22
 
22
23
  public summarize(line: string): string {
23
- if (Logger.isSystemNoise(line)) return "";
24
+ if (line.includes("CATALINA") || line.includes("Using JRE_HOME") || line.includes("Using CLASSPATH")) return "";
24
25
 
25
26
  // Reuso da lógica existente no Logger.summarize, mas aprimorada
26
27
  const startupMatch = line.match(/Server startup in (\[?)(.*?)(\]?)\s*ms/);
27
28
  if (startupMatch) {
28
29
  const time = (parseInt(startupMatch[2]) / 1000).toFixed(1);
29
- return `${Logger.C.green}✔ ${Logger.C.bold}Server started in ${time}s`;
30
+ return `${Colors.success}✔ ${Colors.bold}Servidor iniciado em ${time}s`;
30
31
  }
31
32
 
32
33
  const deployMatch = line.match(/Deployment of web application archive \[(.*?)\] has finished in \[(.*?)\] ms/);
33
34
  if (deployMatch) {
34
- return `${Logger.C.green}✔ Artifacts deployed`;
35
+ return `${Colors.success}✔ Artefatos implantados`;
35
36
  }
36
37
 
37
38
  // Smart Folding para Stack Traces
@@ -40,7 +41,7 @@ export class LogAnalyzer {
40
41
  }
41
42
 
42
43
  if (line.includes("Caused by:")) {
43
- return `${Logger.C.bgRed}${Logger.C.white}${Logger.C.bold} ROOT CAUSE ${Logger.C.reset} ${Logger.C.red}${line.trim()}${Logger.C.reset}`;
44
+ return `${Colors.bgRed}${Colors.white}${Colors.bold} CAUSA RAIZ ${Colors.reset} ${Colors.error}${line.trim()}${Colors.reset}`;
44
45
  }
45
46
 
46
47
  // Hotswap
@@ -66,7 +67,7 @@ export class LogAnalyzer {
66
67
 
67
68
  // Se a linha contém Exception mas não é o 'at ', destaca
68
69
  if (line.includes("Exception:")) {
69
- return `${Logger.C.red}${Logger.C.bold}${line.trim()}${Logger.C.reset}`;
70
+ return `${Colors.error}${Colors.bold}${line.trim()}${Colors.reset}`;
70
71
  }
71
72
 
72
73
  return "";
@@ -77,9 +78,9 @@ export class LogAnalyzer {
77
78
  const isProject = this.projectPrefixes.some(p => trimmed.includes(p));
78
79
 
79
80
  if (isProject) {
80
- return ` ${Logger.C.bold}${Logger.C.warning}${trimmed}${Logger.C.reset}`;
81
+ return ` ${Colors.bold}${Colors.warning}${trimmed}${Colors.reset}`;
81
82
  } else {
82
- return ` ${Logger.C.dim}${trimmed}${Logger.C.reset}`;
83
+ return ` ${Colors.dim}${trimmed}${Colors.reset}`;
83
84
  }
84
85
  }
85
86
 
@@ -87,7 +88,10 @@ export class LogAnalyzer {
87
88
  const level = match[1];
88
89
  let msg = match[3];
89
90
 
90
- if (msg.includes("plugin initialized")) return "";
91
+ // Ignora mensagens de plugin inicializado (são muito verbosas)
92
+ if (msg.toLowerCase().includes("plugin") && msg.toLowerCase().includes("initialized")) {
93
+ return "";
94
+ }
91
95
 
92
96
  if (msg.includes("redefinition") || msg.includes("reloaded") || level === 'RELOAD') {
93
97
  if (msg.includes("Reloading classes [")) {
@@ -95,26 +99,26 @@ export class LogAnalyzer {
95
99
  const classCount = classes.split(",").length;
96
100
  if (classCount > 3) msg = `Reloading ${classCount} classes...`;
97
101
  }
98
- return `${Logger.C.magenta}👀 ${Logger.C.bold}Hotswap:${Logger.C.reset} ${msg.replace(/Class '.*?'/, (m) => Logger.C.bold + m + Logger.C.reset)}`;
102
+ return `${Colors.magenta}👀 ${Colors.bold}Hotswap:${Colors.reset} ${msg.replace(/Class '.*?'/, (m) => Colors.bold + m + Colors.reset)}`;
99
103
  }
100
104
 
101
- let color = Logger.C.primary;
105
+ let color = Colors.primary;
102
106
  let symbol = "●";
103
- if (level === "WARN") { color = Logger.C.warning; symbol = "▲"; }
104
- else if (level === "ERROR") { color = Logger.C.red; symbol = "✖"; }
107
+ if (level === "WARN") { color = Colors.warning; symbol = "▲"; }
108
+ else if (level === "ERROR") { color = Colors.error; symbol = "✖"; }
105
109
 
106
- return `${color}${symbol} ${Logger.C.bold}Hotswap:${Logger.C.reset} ${msg}`;
110
+ return `${color}${symbol} ${Colors.bold}Hotswap:${Colors.reset} ${msg}`;
107
111
  }
108
112
 
109
113
  private formatTomcatLine(match: RegExpMatchArray): string {
110
114
  const label = match[2];
111
115
  let msg = match[4].trim();
112
- if (Logger.isSystemNoise(msg)) return "";
116
+ if (msg.includes("CATALINA") || msg.includes("Using JRE_HOME")) return "";
113
117
 
114
- let color = Logger.C.dim;
118
+ let color = Colors.dim;
115
119
  let symbol = "ℹ";
116
- if (label === "WARNING") { color = Logger.C.warning; symbol = "▲"; }
117
- else if (label === "SEVERE" || label === "ERROR") { color = Logger.C.red; symbol = "✖"; }
120
+ if (label === "WARNING") { color = Colors.warning; symbol = "▲"; }
121
+ else if (label === "SEVERE" || label === "ERROR") { color = Colors.error; symbol = "✖"; }
118
122
 
119
123
  msg = msg.replace(/^(org\.apache|com\.sun|java\..*?|org\.glassfish)\.[a-zA-Z0-9.]+\s/, "").trim();
120
124
  if (!msg) return "";
@@ -127,13 +131,13 @@ export class LogAnalyzer {
127
131
  let msg = match[2].trim();
128
132
  if (msg.includes("Total time:") || msg.includes("Finished at:") || msg.includes("Final Memory:") || msg.includes("-----------------------")) return "";
129
133
 
130
- let color = Logger.C.dim;
134
+ let color = Colors.dim;
131
135
  let symbol = "ℹ";
132
- if (label === "WARNING" || label === "WARN") { color = Logger.C.warning; symbol = "▲"; }
133
- else if (label === "SEVERE" || label === "ERROR") { color = Logger.C.red; symbol = "✖"; }
136
+ if (label === "WARNING" || label === "WARN") { color = Colors.warning; symbol = "▲"; }
137
+ else if (label === "SEVERE" || label === "ERROR") { color = Colors.error; symbol = "✖"; }
134
138
 
135
139
  msg = msg.replace(/^(org\.apache|com\.sun|java\..*?)\.[a-zA-Z0-9.]+\s/, "").trim();
136
- if (!msg || msg === "]" || msg.includes("Compilation failure")) return "";
140
+ if (!msg || msg === "]") return "";
137
141
 
138
142
  return `${color}${symbol} ${msg}`;
139
143
  }