@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
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Sistema de Logging do XAVVA CLI
3
+ *
4
+ * Exporta todas as funcionalidades de logging para uso em toda a aplicação.
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * import { Logger, OperationLogger, ProgressLogger, TableLogger } from '../logging';
9
+ *
10
+ * // Log simples
11
+ * Logger.info('Iniciando processo');
12
+ * Logger.success('Concluído');
13
+ *
14
+ * // Operação complexa
15
+ * const op = new OperationLogger('deploy');
16
+ * op.start();
17
+ * const buildStep = op.step('build');
18
+ * await build();
19
+ * buildStep.success();
20
+ * op.complete();
21
+ *
22
+ * // Progresso
23
+ * const progress = new ProgressLogger('Download', { total: 100, unit: 'MB' });
24
+ * progress.update(50);
25
+ * progress.complete();
26
+ *
27
+ * // Tabela
28
+ * const table = new TableLogger(['Nome', 'Versão']);
29
+ * table.add(['Spring', '5.3.0']);
30
+ * table.print();
31
+ * ```
32
+ */
33
+
34
+ // Tipos
35
+ export type {
36
+ LogLevel,
37
+ LogOutputMode,
38
+ LogContext,
39
+ LogEntry,
40
+ LoggerConfig,
41
+ RateLimitEntry,
42
+ OperationStep,
43
+ TableColumn,
44
+ TableRow,
45
+ } from './types';
46
+
47
+ // Cores e utilitários
48
+ export {
49
+ Colors,
50
+ Icons,
51
+ colorize,
52
+ stripAnsi,
53
+ visualWidth,
54
+ padText,
55
+ truncateText,
56
+ getIcon,
57
+ supportsColor,
58
+ } from './colors';
59
+
60
+ // Constantes
61
+ export {
62
+ DEFAULT_CONFIG,
63
+ LOG_LEVELS,
64
+ LEVEL_COLORS,
65
+ LEVEL_ICONS,
66
+ LAYOUT,
67
+ NOISE_PATTERNS,
68
+ ESSENTIAL_PATTERNS,
69
+ SPINNER_FRAMES,
70
+ SPINNER_INTERVAL,
71
+ FILE_LOG,
72
+ } from './constants';
73
+
74
+ // Formatadores
75
+ export {
76
+ formatEntry,
77
+ formatStatusLine,
78
+ formatSection,
79
+ formatConfig,
80
+ formatUrl,
81
+ formatFile,
82
+ } from './formatters';
83
+
84
+ // Logger principal
85
+ export { Logger, logger } from './Logger';
86
+
87
+ // Loggers especializados
88
+ export { OperationLogger, OperationStepLogger, createOperation } from './OperationLogger';
89
+ export { ProgressLogger, createProgress } from './ProgressLogger';
90
+ export { TableLogger, createTable, printTable } from './TableLogger';
91
+
92
+ // FileLogger
93
+ export { FileLogger, getFileLogger, configureFileLogger } from './FileLogger';
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Tipos do sistema de logging
3
+ */
4
+
5
+ export type LogLevel = 'silent' | 'error' | 'warn' | 'info' | 'success' | 'debug' | 'trace' | 'silly';
6
+
7
+ export type LogOutputMode = 'pretty' | 'json' | 'minimal' | 'silent';
8
+
9
+ export interface LogContext {
10
+ timestamp?: boolean;
11
+ traceId?: string;
12
+ indent?: number;
13
+ prefix?: string;
14
+ metadata?: Record<string, unknown>;
15
+ }
16
+
17
+ export interface LogEntry {
18
+ level: LogLevel;
19
+ message: string;
20
+ timestamp: Date;
21
+ context?: LogContext;
22
+ metadata?: Record<string, unknown>;
23
+ }
24
+
25
+ export interface LoggerConfig {
26
+ level: LogLevel;
27
+ mode: LogOutputMode;
28
+ timestamps: boolean;
29
+ colors: boolean;
30
+ icons: boolean;
31
+ fileLogging: boolean;
32
+ logDir: string;
33
+ maxLogFiles: number;
34
+ rateLimitWindowMs: number;
35
+ maxDuplicateLogs: number;
36
+ }
37
+
38
+ export interface RateLimitEntry {
39
+ message: string;
40
+ count: number;
41
+ firstSeen: number;
42
+ lastSeen: number;
43
+ }
44
+
45
+ export interface OperationStep {
46
+ id: string;
47
+ name: string;
48
+ status: 'pending' | 'running' | 'success' | 'failed';
49
+ startTime?: Date;
50
+ endTime?: Date;
51
+ message?: string;
52
+ error?: Error;
53
+ }
54
+
55
+ export interface TableColumn {
56
+ header: string;
57
+ align?: 'left' | 'center' | 'right';
58
+ width?: number;
59
+ }
60
+
61
+ export interface TableRow {
62
+ cells: string[];
63
+ styles?: string[];
64
+ }
@@ -0,0 +1,325 @@
1
+ /**
2
+ * Gerenciador de Plugins do XAVVA CLI
3
+ *
4
+ * Responsável por:
5
+ * - Carregar plugins de npm ou caminhos locais
6
+ * - Executar hooks em pontos específicos
7
+ * - Gerenciar comandos de plugins
8
+ */
9
+
10
+ import path from "path";
11
+ import { existsSync } from "fs";
12
+ import { mkdir, writeFile, readFile } from "fs/promises";
13
+ import os from "os";
14
+ import type { AppConfig } from "../types/config";
15
+ import { Logger } from "../logging";
16
+ import type {
17
+ XavvaPlugin,
18
+ LoadedPlugin,
19
+ PluginConfig,
20
+ BuildContext,
21
+ DeployContext,
22
+ TestContext,
23
+ } from "./types";
24
+
25
+ export class PluginManager {
26
+ private plugins: LoadedPlugin[] = [];
27
+ private logger = Logger.getInstance();
28
+ private pluginsDir: string;
29
+ private config: AppConfig;
30
+
31
+ constructor(config: AppConfig) {
32
+ this.config = config;
33
+ this.pluginsDir = path.join(os.homedir(), ".xavva", "plugins");
34
+ }
35
+
36
+ /**
37
+ * Carrega todos os plugins configurados
38
+ */
39
+ async loadPlugins(): Promise<void> {
40
+ const pluginConfigs = this.config.project.plugins as PluginConfig[] || [];
41
+
42
+ if (pluginConfigs.length === 0) {
43
+ this.logger.debug("Nenhum plugin configurado");
44
+ return;
45
+ }
46
+
47
+ this.logger.section(`Carregando ${pluginConfigs.length} plugin(s)`);
48
+
49
+ for (const pluginConfig of pluginConfigs) {
50
+ try {
51
+ await this.loadPlugin(pluginConfig);
52
+ } catch (error) {
53
+ this.logger.error(`Falha ao carregar plugin ${pluginConfig.name}: ${(error as Error).message}`);
54
+ }
55
+ }
56
+
57
+ this.logger.success(`${this.plugins.length} plugin(s) carregado(s)`);
58
+ }
59
+
60
+ /**
61
+ * Carrega um plugin específico
62
+ */
63
+ private async loadPlugin(config: PluginConfig): Promise<void> {
64
+ const { name, path: pluginPath, config: pluginConfigData } = config;
65
+
66
+ this.logger.step(`Carregando: ${name}`);
67
+
68
+ // Resolve caminho do plugin
69
+ const resolvedPath = this.resolvePluginPath(name, pluginPath);
70
+
71
+ // Importa plugin
72
+ const pluginModule = await import(resolvedPath);
73
+ const plugin: XavvaPlugin = pluginModule.default || pluginModule;
74
+
75
+ // Valida plugin
76
+ this.validatePlugin(plugin);
77
+
78
+ // Inicializa se necessário
79
+ if (plugin.initialize) {
80
+ await plugin.initialize(this.config);
81
+ }
82
+
83
+ // Registra plugin
84
+ this.plugins.push({
85
+ plugin,
86
+ path: resolvedPath,
87
+ config: pluginConfigData,
88
+ });
89
+
90
+ this.logger.info(` ✓ ${plugin.name} v${plugin.version}`);
91
+ if (plugin.description) {
92
+ this.logger.info(` ${plugin.description}`);
93
+ }
94
+ }
95
+
96
+ /**
97
+ * Resolve caminho do plugin
98
+ */
99
+ private resolvePluginPath(name: string, customPath?: string): string {
100
+ // Caminho customizado tem prioridade
101
+ if (customPath) {
102
+ if (customPath.startsWith("./") || customPath.startsWith("../")) {
103
+ return path.resolve(process.cwd(), customPath);
104
+ }
105
+ return customPath;
106
+ }
107
+
108
+ // Tenta carregar de node_modules
109
+ const npmPath = path.join(process.cwd(), "node_modules", name);
110
+ if (existsSync(npmPath)) {
111
+ return npmPath;
112
+ }
113
+
114
+ // Tenta carregar do diretório de plugins do Xavva
115
+ const xavvaPluginPath = path.join(this.pluginsDir, name);
116
+ if (existsSync(xavvaPluginPath)) {
117
+ return xavvaPluginPath;
118
+ }
119
+
120
+ // Tenta carregar como caminho relativo
121
+ const relativePath = path.join(process.cwd(), name);
122
+ if (existsSync(relativePath)) {
123
+ return relativePath;
124
+ }
125
+
126
+ throw new Error(`Plugin não encontrado: ${name}`);
127
+ }
128
+
129
+ /**
130
+ * Valida estrutura do plugin
131
+ */
132
+ private validatePlugin(plugin: XavvaPlugin): void {
133
+ if (!plugin.name) {
134
+ throw new Error("Plugin deve ter um nome");
135
+ }
136
+
137
+ if (!plugin.version) {
138
+ throw new Error("Plugin deve ter uma versão");
139
+ }
140
+ }
141
+
142
+ /**
143
+ * Executa hook beforeBuild em todos os plugins
144
+ */
145
+ async executeBeforeBuild(context: BuildContext): Promise<void> {
146
+ for (const { plugin } of this.plugins) {
147
+ if (plugin.hooks?.beforeBuild) {
148
+ try {
149
+ await plugin.hooks.beforeBuild(context);
150
+ } catch (error) {
151
+ this.logger.warn(`Plugin ${plugin.name} falhou em beforeBuild: ${(error as Error).message}`);
152
+ }
153
+ }
154
+ }
155
+ }
156
+
157
+ /**
158
+ * Executa hook afterBuild em todos os plugins
159
+ */
160
+ async executeAfterBuild(context: BuildContext, success: boolean): Promise<void> {
161
+ for (const { plugin } of this.plugins) {
162
+ if (plugin.hooks?.afterBuild) {
163
+ try {
164
+ await plugin.hooks.afterBuild(context, success);
165
+ } catch (error) {
166
+ this.logger.warn(`Plugin ${plugin.name} falhou em afterBuild: ${(error as Error).message}`);
167
+ }
168
+ }
169
+ }
170
+ }
171
+
172
+ /**
173
+ * Executa hook beforeDeploy em todos os plugins
174
+ */
175
+ async executeBeforeDeploy(context: DeployContext): Promise<void> {
176
+ for (const { plugin } of this.plugins) {
177
+ if (plugin.hooks?.beforeDeploy) {
178
+ try {
179
+ await plugin.hooks.beforeDeploy(context);
180
+ } catch (error) {
181
+ this.logger.warn(`Plugin ${plugin.name} falhou em beforeDeploy: ${(error as Error).message}`);
182
+ }
183
+ }
184
+ }
185
+ }
186
+
187
+ /**
188
+ * Executa hook afterDeploy em todos os plugins
189
+ */
190
+ async executeAfterDeploy(context: DeployContext, success: boolean): Promise<void> {
191
+ for (const { plugin } of this.plugins) {
192
+ if (plugin.hooks?.afterDeploy) {
193
+ try {
194
+ await plugin.hooks.afterDeploy(context, success);
195
+ } catch (error) {
196
+ this.logger.warn(`Plugin ${plugin.name} falhou em afterDeploy: ${(error as Error).message}`);
197
+ }
198
+ }
199
+ }
200
+ }
201
+
202
+ /**
203
+ * Executa hook beforeTest em todos os plugins
204
+ */
205
+ async executeBeforeTest(context: TestContext): Promise<void> {
206
+ for (const { plugin } of this.plugins) {
207
+ if (plugin.hooks?.beforeTest) {
208
+ try {
209
+ await plugin.hooks.beforeTest(context);
210
+ } catch (error) {
211
+ this.logger.warn(`Plugin ${plugin.name} falhou em beforeTest: ${(error as Error).message}`);
212
+ }
213
+ }
214
+ }
215
+ }
216
+
217
+ /**
218
+ * Executa hook afterTest em todos os plugins
219
+ */
220
+ async executeAfterTest(context: TestContext, success: boolean): Promise<void> {
221
+ for (const { plugin } of this.plugins) {
222
+ if (plugin.hooks?.afterTest) {
223
+ try {
224
+ await plugin.hooks.afterTest(context, success);
225
+ } catch (error) {
226
+ this.logger.warn(`Plugin ${plugin.name} falhou em afterTest: ${(error as Error).message}`);
227
+ }
228
+ }
229
+ }
230
+ }
231
+
232
+ /**
233
+ * Obtém comandos de todos os plugins
234
+ */
235
+ getPluginCommands(): Map<string, import("../commands/Command").Command> {
236
+ const commands = new Map<string, import("../commands/Command").Command>();
237
+
238
+ for (const { plugin } of this.plugins) {
239
+ if (plugin.commands) {
240
+ for (const command of plugin.commands) {
241
+ // Assume que comando tem nome ou usa classe
242
+ const name = (command as any).name || command.constructor.name.toLowerCase();
243
+ commands.set(name, command);
244
+ }
245
+ }
246
+ }
247
+
248
+ return commands;
249
+ }
250
+
251
+ /**
252
+ * Lista plugins carregados
253
+ */
254
+ listPlugins(): Array<{ name: string; version: string; description?: string }> {
255
+ return this.plugins.map(({ plugin }) => ({
256
+ name: plugin.name,
257
+ version: plugin.version,
258
+ description: plugin.description,
259
+ }));
260
+ }
261
+
262
+ /**
263
+ * Destrói todos os plugins
264
+ */
265
+ async destroy(): Promise<void> {
266
+ for (const { plugin } of this.plugins) {
267
+ if (plugin.destroy) {
268
+ try {
269
+ await plugin.destroy();
270
+ } catch (error) {
271
+ this.logger.warn(`Erro ao destruir plugin ${plugin.name}: ${(error as Error).message}`);
272
+ }
273
+ }
274
+ }
275
+ this.plugins = [];
276
+ }
277
+
278
+ /**
279
+ * Instala plugin via npm
280
+ */
281
+ async installPlugin(name: string): Promise<void> {
282
+ this.logger.step(`Instalando plugin: ${name}`);
283
+
284
+ // Cria diretório se não existe
285
+ await mkdir(this.pluginsDir, { recursive: true });
286
+
287
+ // Executa npm install
288
+ const proc = Bun.spawn([
289
+ "npm", "install", name, "--prefix", this.pluginsDir, "--no-save"
290
+ ], {
291
+ stdout: "pipe",
292
+ stderr: "pipe",
293
+ });
294
+
295
+ const exitCode = await proc.exited;
296
+
297
+ if (exitCode !== 0) {
298
+ const error = await new Response(proc.stderr).text();
299
+ throw new Error(`npm install falhou: ${error}`);
300
+ }
301
+
302
+ this.logger.success(`Plugin ${name} instalado`);
303
+ }
304
+
305
+ /**
306
+ * Remove plugin
307
+ */
308
+ async uninstallPlugin(name: string): Promise<void> {
309
+ this.logger.step(`Removendo plugin: ${name}`);
310
+
311
+ const proc = Bun.spawn([
312
+ "npm", "uninstall", name, "--prefix", this.pluginsDir
313
+ ], {
314
+ stdout: "pipe",
315
+ stderr: "pipe",
316
+ });
317
+
318
+ await proc.exited;
319
+
320
+ // Remove da lista de plugins carregados
321
+ this.plugins = this.plugins.filter(p => p.plugin.name !== name);
322
+
323
+ this.logger.success(`Plugin ${name} removido`);
324
+ }
325
+ }
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Tipos para o Sistema de Plugins do XAVVA CLI
3
+ */
4
+
5
+ import type { Command } from "../commands/Command";
6
+ import type { AppConfig } from "../types/config";
7
+ import type { z } from "zod";
8
+
9
+ // Contextos de hooks
10
+ export interface BuildContext {
11
+ config: AppConfig;
12
+ incremental: boolean;
13
+ changedFiles?: string[];
14
+ }
15
+
16
+ export interface DeployContext {
17
+ config: AppConfig;
18
+ targetPath: string;
19
+ }
20
+
21
+ export interface TestContext {
22
+ config: AppConfig;
23
+ filter?: string;
24
+ coverage: boolean;
25
+ }
26
+
27
+ // Hook handlers
28
+ export type BeforeBuildHook = (context: BuildContext) => Promise<void> | void;
29
+ export type AfterBuildHook = (context: BuildContext, success: boolean) => Promise<void> | void;
30
+ export type BeforeDeployHook = (context: DeployContext) => Promise<void> | void;
31
+ export type AfterDeployHook = (context: DeployContext, success: boolean) => Promise<void> | void;
32
+ export type BeforeTestHook = (context: TestContext) => Promise<void> | void;
33
+ export type AfterTestHook = (context: TestContext, success: boolean) => Promise<void> | void;
34
+
35
+ // Interface do plugin
36
+ export interface XavvaPlugin {
37
+ /** Nome único do plugin */
38
+ name: string;
39
+
40
+ /** Versão do plugin (semver) */
41
+ version: string;
42
+
43
+ /** Descrição */
44
+ description?: string;
45
+
46
+ /** Comandos adicionados pelo plugin */
47
+ commands?: Command[];
48
+
49
+ /** Hooks */
50
+ hooks?: {
51
+ beforeBuild?: BeforeBuildHook;
52
+ afterBuild?: AfterBuildHook;
53
+ beforeDeploy?: BeforeDeployHook;
54
+ afterDeploy?: AfterDeployHook;
55
+ beforeTest?: BeforeTestHook;
56
+ afterTest?: AfterTestHook;
57
+ };
58
+
59
+ /** Schema de configuração estendida */
60
+ configSchema?: z.ZodSchema;
61
+
62
+ /** Inicialização do plugin */
63
+ initialize?(config: AppConfig): Promise<void> | void;
64
+
65
+ /** Cleanup ao finalizar */
66
+ destroy?(): Promise<void> | void;
67
+ }
68
+
69
+ // Metadados de plugin carregado
70
+ export interface LoadedPlugin {
71
+ plugin: XavvaPlugin;
72
+ path: string;
73
+ config?: Record<string, unknown>;
74
+ }
75
+
76
+ // Configuração de plugin no xavva.json
77
+ export interface PluginConfig {
78
+ name: string;
79
+ version?: string;
80
+ path?: string;
81
+ config?: Record<string, unknown>;
82
+ }
@@ -1,7 +1,7 @@
1
1
  import fs from "fs";
2
2
  import path from "path";
3
3
  import type { TomcatConfig } from "../types";
4
- import { Logger } from "../utils/ui";
4
+ import { Logger } from "../logging";
5
5
  import { AuditError } from "../errors/XavvaError";
6
6
 
7
7
  export interface Vulnerability {
@@ -47,6 +47,8 @@ interface OSVResponse {
47
47
  }
48
48
 
49
49
  export class AuditService {
50
+ private logger = Logger.getInstance();
51
+
50
52
  constructor(private tomcatConfig: TomcatConfig) {}
51
53
 
52
54
  async runAudit(appName: string): Promise<JarAuditResult[]> {
@@ -59,7 +61,7 @@ export class AuditService {
59
61
  const jars = fs.readdirSync(libPath).filter(f => f.endsWith(".jar"));
60
62
  const results: JarAuditResult[] = [];
61
63
 
62
- const stopSpinner = Logger.spinner(`Auditando ${jars.length} dependências`);
64
+ const stopSpinner = this.logger.spinner(`Auditando ${jars.length} dependências`);
63
65
 
64
66
  const chunkSize = 10;
65
67
  for (let i = 0; i < jars.length; i += chunkSize) {
@@ -69,7 +71,7 @@ export class AuditService {
69
71
  results.push(...chunkResults);
70
72
  }
71
73
 
72
- stopSpinner();
74
+ stopSpinner.stop();
73
75
  return results;
74
76
  }
75
77
 
@@ -1,11 +1,13 @@
1
1
  import { readdirSync, existsSync, statSync, mkdirSync, promises as fs } from "fs";
2
2
  import path from "path";
3
3
  import type { ProjectConfig, TomcatConfig } from "../types/config";
4
- import { Logger } from "../utils/ui";
4
+ import { Logger } from "../logging";
5
5
  import { BuildCacheService } from "./BuildCacheService";
6
6
  import { ProjectService } from "./ProjectService";
7
7
 
8
8
  export class BuildService {
9
+ private logger = Logger.getInstance();
10
+
9
11
  constructor(
10
12
  private projectConfig: ProjectConfig,
11
13
  private tomcatConfig: TomcatConfig,
@@ -40,7 +42,7 @@ export class BuildService {
40
42
 
41
43
  if (useCache && !incremental && !this.projectConfig.skipBuild) {
42
44
  if (!this.projectConfig.clean && !this.cache.shouldRebuild(this.projectConfig.buildTool, this.projectService)) {
43
- Logger.success("Build cache hit! Skipping full build.");
45
+ this.logger.success("Cache de build atingido! Pulando build completo.");
44
46
  return;
45
47
  }
46
48
  }
@@ -96,7 +98,7 @@ export class BuildService {
96
98
  env.GRADLE_OPTS = "-Xmx1024m -Dorg.gradle.daemon=true";
97
99
  }
98
100
 
99
- const stopSpinner = (this.projectConfig.verbose) ? () => {} : Logger.spinner(incremental ? "Incremental compilation" : "Full project build");
101
+ const spinner = this.projectConfig.verbose ? null : this.logger.spinner(incremental ? "Compilação incremental" : "Build completo do projeto");
100
102
 
101
103
  // No Windows, comandos .cmd/.bat muitas vezes precisam de shell: true no Bun.spawn ou o nome exato.
102
104
  // Vamos usar o nome exato mvn.cmd/gradle.bat que é mais seguro que shell: true
@@ -114,14 +116,14 @@ export class BuildService {
114
116
  }
115
117
 
116
118
  await proc.exited;
117
- stopSpinner();
119
+ spinner?.stop();
118
120
 
119
121
  if (proc.exitCode !== 0) {
120
122
  if (!this.projectConfig.verbose) {
121
123
  const err = await new Response(proc.stderr).text();
122
- Logger.log(err);
124
+ console.log(err);
123
125
  }
124
- Logger.error(`${this.projectConfig.buildTool.toUpperCase()} build failed!`);
126
+ this.logger.error(`${this.projectConfig.buildTool.toUpperCase()} build falhou!`);
125
127
  throw new Error("Falha no build do Java!");
126
128
  }
127
129
 
@@ -141,11 +143,11 @@ export class BuildService {
141
143
 
142
144
  if (existsSync(buildDir)) {
143
145
  try {
144
- Logger.step(`Cleaning ${path.basename(buildDir)}/ directory...`);
146
+ this.logger.debug(`Limpando diretório ${path.basename(buildDir)}/...`);
145
147
  await fs.rm(buildDir, { recursive: true, force: true });
146
- Logger.debug(`Removed ${buildDir}`);
148
+ // Directory removed
147
149
  } catch (e) {
148
- Logger.warn(`Could not fully remove ${buildDir}, continuing...`);
150
+ this.logger.warn(`Não foi possível remover completamente ${buildDir}, continuando...`);
149
151
  }
150
152
  }
151
153
  }
@@ -219,7 +221,7 @@ export class BuildService {
219
221
  if (syncedCount.value === 0) {
220
222
  await this.fastSync(sourceDir, targetLib);
221
223
  } else if (!this.projectConfig.quiet) {
222
- Logger.info("sync", `${syncedCount.value} classe(s) sincronizada(s)`);
224
+ this.logger.info(`${syncedCount.value} classe(s) sincronizada(s)`);
223
225
  }
224
226
  }
225
227
 
@@ -324,15 +326,11 @@ export class BuildService {
324
326
 
325
327
  if (!this.projectConfig.verbose) {
326
328
  // Modo não-verbose: usa sumarização existente
327
- const formatted = Logger.formatBuildLog(cleanLine, buildTool);
329
+ const formatted = this.logger.constructor.name === 'Logger' ? '' : cleanLine;
328
330
  if (formatted) console.log(formatted);
329
331
  } else {
330
- // Modo verbose: formata mas mantém estrutura
331
- const formatted = Logger.formatBuildLog(cleanLine, buildTool);
332
- if (formatted) {
333
- console.log(formatted);
334
- }
335
- // Silencia linhas que são noise puro
332
+ // Modo verbose: mostra todas as linhas
333
+ console.log(` ${cleanLine.slice(0, 100)}`);
336
334
  }
337
335
  }
338
336
  }