@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,54 +1,132 @@
1
1
  /**
2
2
  * Constantes da aplicação XAVVA CLI
3
3
  *
4
- * Centraliza valores mágicos para facilitar manutenção e configuração.
4
+ * ⚠️ NOTA: Este arquivo re-exporta constantes de src/config/versions.ts
5
+ * para manter compatibilidade. Novo código deve importar diretamente
6
+ * de src/config/versions.ts
7
+ *
8
+ * @deprecated Importe diretamente de src/config/versions.ts
5
9
  */
6
10
 
7
- // Ports padrão
11
+ // Re-exportar todas as constantes centralizadas
12
+ export {
13
+ VERSIONS,
14
+ PORTS,
15
+ TIMEOUTS,
16
+ LIMITS,
17
+ DASHBOARD,
18
+ BUILD,
19
+ EXIT_CODES,
20
+ PATHS,
21
+ CACHE,
22
+ // Types
23
+ type TomcatVersion,
24
+ // Functions
25
+ getHotswapAgentUrl,
26
+ isSupportedTomcatVersion,
27
+ getAvailableTomcatVersions,
28
+ getTomcatSha512,
29
+ } from "../config/versions";
30
+
31
+ // ============================================
32
+ // ALIASES LEGACY (para compatibilidade)
33
+ // ============================================
34
+
35
+ /** @deprecated Use PORTS.DEFAULT_TOMCAT */
8
36
  export const DEFAULT_TOMCAT_PORT = 8080;
37
+
38
+ /** @deprecated Use PORTS.DEFAULT_DEBUG */
9
39
  export const DEFAULT_DEBUG_PORT = 5005;
10
40
 
11
- // Timeouts (em milissegundos)
41
+ /** @deprecated Use TIMEOUTS.SHUTDOWN */
12
42
  export const TIMEOUT_SHUTDOWN_MS = 5000;
43
+
44
+ /** @deprecated Use TIMEOUTS.WATCHER_DEBOUNCE */
13
45
  export const WATCHER_DEBOUNCE_MS = 1500;
46
+
47
+ /** @deprecated Use TIMEOUTS.COOLING */
14
48
  export const WATCHER_COOLING_MS = 1000;
49
+
50
+ /** @deprecated Use TIMEOUTS.BROWSER_OPEN */
15
51
  export const BROWSER_OPEN_DELAY_MS = 800;
52
+
53
+ /** @deprecated Use TIMEOUTS.DEPLOY_HEALTH_CHECK */
16
54
  export const DEPLOY_HEALTH_CHECK_DELAY_MS = 1500;
55
+
56
+ /** @deprecated Use TIMEOUTS.HOTSWAP */
17
57
  export const HOTSWAP_DELAY_MS = 500;
58
+
59
+ /** @deprecated Use TIMEOUTS.TOMCAT_CLEAN_RETRY */
18
60
  export const TOMCAT_CLEAN_RETRY_DELAY_MS = 50;
19
61
 
20
- // Tamanhos e limites
62
+ /** @deprecated Use LIMITS.MAX_LOG_SCROLLBUFFER */
21
63
  export const MAX_LOG_SCROLLBUFFER = 1000;
64
+
65
+ /** @deprecated Use LIMITS.MAX_BUILD_ERRORS_SHOWN */
22
66
  export const MAX_BUILD_ERRORS_SHOWN = 15;
67
+
68
+ /** @deprecated Use LIMITS.MAX_HISTORY_ITEMS */
23
69
  export const MAX_HISTORY_ITEMS = 10;
70
+
71
+ /** @deprecated Use LIMITS.JAR_INTEGRITY_BUFFER_SIZE */
24
72
  export const JAR_INTEGRITY_BUFFER_SIZE = 1024;
73
+
74
+ /** @deprecated Use LIMITS.JAR_MIN_VALID_SIZE */
25
75
  export const JAR_MIN_VALID_SIZE = 1000;
76
+
77
+ /** @deprecated Use LIMITS.ZIP_EOCD_SIGNATURE_SIZE */
26
78
  export const ZIP_EOCD_SIGNATURE_SIZE = 4;
27
79
 
28
- // Dashboard
80
+ /** @deprecated Use DASHBOARD.REFRESH_INTERVAL_MS */
29
81
  export const DASHBOARD_REFRESH_INTERVAL_MS = 1000;
82
+
83
+ /** @deprecated Use DASHBOARD.LOG_SLICE_LINES */
30
84
  export const DASHBOARD_LOG_SLICE_LINES = 1000;
31
85
 
32
- // Build
86
+ /** @deprecated Use BUILD.MAVEN_PARALLEL_THREADS */
33
87
  export const MAVEN_PARALLEL_THREADS = "1C";
88
+
89
+ /** @deprecated Use BUILD.JVM_MEMORY_OPTS */
34
90
  export const JVM_MEMORY_OPTS = "-Xms512m -Xmx1024m -XX:+UseParallelGC";
91
+
92
+ /** @deprecated Use BUILD.GRADLE_MEMORY_OPTS */
35
93
  export const GRADLE_MEMORY_OPTS = "-Xmx1024m -Dorg.gradle.daemon=true";
36
94
 
37
- // Exit codes
95
+ /** @deprecated Use EXIT_CODES.SUCCESS */
38
96
  export const EXIT_SUCCESS = 0;
97
+
98
+ /** @deprecated Use EXIT_CODES.GENERIC_ERROR */
39
99
  export const EXIT_GENERIC_ERROR = 1;
100
+
101
+ /** @deprecated Use EXIT_CODES.INVALID_COMMAND */
40
102
  export const EXIT_INVALID_COMMAND = 2;
103
+
104
+ /** @deprecated Use EXIT_CODES.BUILD_FAILED */
41
105
  export const EXIT_BUILD_FAILED = 3;
106
+
107
+ /** @deprecated Use EXIT_CODES.DEPLOY_FAILED */
42
108
  export const EXIT_DEPLOY_FAILED = 4;
109
+
110
+ /** @deprecated Use EXIT_CODES.SIGINT */
43
111
  export const EXIT_SIGINT = 130;
44
112
 
45
- // File patterns
113
+ /** @deprecated Use PATHS.JAVA_FILE_PATTERN */
46
114
  export const JAVA_FILE_PATTERN = "**/*.java";
115
+
116
+ /** @deprecated Use PATHS.WAR_EXTENSION */
47
117
  export const WAR_EXTENSION = ".war";
118
+
119
+ /** @deprecated Use PATHS.JAR_EXTENSION */
48
120
  export const JAR_EXTENSION = ".jar";
49
121
 
50
- // Directories
122
+ /** @deprecated Use PATHS.XAVVA_DIR */
51
123
  export const XAVVA_DIR = ".xavva";
124
+
125
+ /** @deprecated Use PATHS.TARGET_DIR */
52
126
  export const TARGET_DIR = "target";
127
+
128
+ /** @deprecated Use PATHS.BUILD_DIR */
53
129
  export const BUILD_DIR = "build";
130
+
131
+ /** @deprecated Use PATHS.WEBAPP_DIR */
54
132
  export const WEBAPP_DIR = "webapps";
@@ -0,0 +1,192 @@
1
+ /**
2
+ * Utilitários para modo Dry-Run (simulação)
3
+ *
4
+ * Permite visualizar o que seria executado sem realmente executar
5
+ */
6
+
7
+ import { Logger } from "../logging";
8
+
9
+ export interface DryRunAction {
10
+ type: "command" | "file" | "network" | "config" | "warning";
11
+ description: string;
12
+ details?: string[];
13
+ }
14
+
15
+ export class DryRunSimulator {
16
+ private actions: DryRunAction[] = [];
17
+ private logger = Logger.getInstance();
18
+
19
+ /**
20
+ * Registra uma ação que seria executada
21
+ */
22
+ addCommand(command: string, args: string[] = []): void {
23
+ this.actions.push({
24
+ type: "command",
25
+ description: `Executar: ${command} ${args.join(" ")}`,
26
+ details: [`Comando: ${command}`, `Args: ${args.join(" ") || "(nenhum)"}`],
27
+ });
28
+ }
29
+
30
+ /**
31
+ * Registra uma operação de arquivo
32
+ */
33
+ addFileOperation(operation: "copy" | "move" | "delete" | "create", from: string, to?: string): void {
34
+ const descriptions: Record<string, string> = {
35
+ copy: `Copiar: ${from} → ${to}`,
36
+ move: `Mover: ${from} → ${to}`,
37
+ delete: `Excluir: ${from}`,
38
+ create: `Criar: ${from}`,
39
+ };
40
+
41
+ this.actions.push({
42
+ type: "file",
43
+ description: descriptions[operation],
44
+ details: [from, to].filter(Boolean),
45
+ });
46
+ }
47
+
48
+ /**
49
+ * Registra uma requisição de rede
50
+ */
51
+ addNetworkRequest(method: string, url: string, body?: string): void {
52
+ this.actions.push({
53
+ type: "network",
54
+ description: `${method.toUpperCase()} ${url}`,
55
+ details: body ? [`Body: ${body}`] : undefined,
56
+ });
57
+ }
58
+
59
+ /**
60
+ * Registra uma mudança de configuração
61
+ */
62
+ addConfigChange(key: string, oldValue: string, newValue: string): void {
63
+ this.actions.push({
64
+ type: "config",
65
+ description: `Config: ${key} = ${newValue}`,
66
+ details: [`Anterior: ${oldValue}`, `Novo: ${newValue}`],
67
+ });
68
+ }
69
+
70
+ /**
71
+ * Adiciona um aviso
72
+ */
73
+ addWarning(message: string): void {
74
+ this.actions.push({
75
+ type: "warning",
76
+ description: `⚠️ ${message}`,
77
+ });
78
+ }
79
+
80
+ /**
81
+ * Mostra o relatório de simulação
82
+ */
83
+ printReport(): void {
84
+ this.logger.section("Modo Dry-Run (Simulação)");
85
+ this.logger.info("Nenhuma alteração será feita. Ações que seriam executadas:");
86
+ this.logger.newline();
87
+
88
+ // Agrupa por tipo
89
+ const byType: Record<string, DryRunAction[]> = {};
90
+ for (const action of this.actions) {
91
+ if (!byType[action.type]) byType[action.type] = [];
92
+ byType[action.type].push(action);
93
+ }
94
+
95
+ // Mostra comandos
96
+ if (byType["command"]) {
97
+ this.logger.info("📋 Comandos:");
98
+ for (const action of byType["command"]) {
99
+ this.logger.info(` $ ${action.description}`);
100
+ }
101
+ this.logger.newline();
102
+ }
103
+
104
+ // Mostra operações de arquivo
105
+ if (byType["file"]) {
106
+ this.logger.info("📁 Arquivos:");
107
+ for (const action of byType["file"]) {
108
+ this.logger.info(` ${action.description}`);
109
+ }
110
+ this.logger.newline();
111
+ }
112
+
113
+ // Mostra requisições de rede
114
+ if (byType["network"]) {
115
+ this.logger.info("🌐 Rede:");
116
+ for (const action of byType["network"]) {
117
+ this.logger.info(` ${action.description}`);
118
+ }
119
+ this.logger.newline();
120
+ }
121
+
122
+ // Mostra mudanças de config
123
+ if (byType["config"]) {
124
+ this.logger.info("⚙️ Configurações:");
125
+ for (const action of byType["config"]) {
126
+ this.logger.info(` ${action.description}`);
127
+ if (action.details) {
128
+ for (const detail of action.details) {
129
+ this.logger.info(` ${detail}`);
130
+ }
131
+ }
132
+ }
133
+ this.logger.newline();
134
+ }
135
+
136
+ // Mostra avisos
137
+ if (byType["warning"]) {
138
+ this.logger.warn("⚠️ Avisos:");
139
+ for (const action of byType["warning"]) {
140
+ this.logger.warn(` ${action.description}`);
141
+ }
142
+ this.logger.newline();
143
+ }
144
+
145
+ this.logger.divider();
146
+ this.logger.info(`Total de ações: ${this.actions.length}`);
147
+ }
148
+
149
+ /**
150
+ * Limpa as ações registradas
151
+ */
152
+ clear(): void {
153
+ this.actions = [];
154
+ }
155
+
156
+ /**
157
+ * Retorna todas as ações
158
+ */
159
+ getActions(): DryRunAction[] {
160
+ return [...this.actions];
161
+ }
162
+ }
163
+
164
+ // Singleton global
165
+ let globalSimulator: DryRunSimulator | null = null;
166
+
167
+ export function getDryRunSimulator(): DryRunSimulator {
168
+ if (!globalSimulator) {
169
+ globalSimulator = new DryRunSimulator();
170
+ }
171
+ return globalSimulator;
172
+ }
173
+
174
+ export function resetDryRunSimulator(): void {
175
+ globalSimulator = null;
176
+ }
177
+
178
+ /**
179
+ * Wrapper para executar função em modo dry-run ou real
180
+ */
181
+ export async function withDryRun<T>(
182
+ isDryRun: boolean,
183
+ fn: () => Promise<T>,
184
+ simulator?: DryRunSimulator
185
+ ): Promise<T | void> {
186
+ if (isDryRun) {
187
+ const sim = simulator || getDryRunSimulator();
188
+ sim.printReport();
189
+ return;
190
+ }
191
+ return fn();
192
+ }
@@ -15,6 +15,8 @@ import {
15
15
  TIMEOUT_SHUTDOWN_MS
16
16
  } from "./constants";
17
17
 
18
+ import { Logger } from "../logging";
19
+
18
20
  export type ExitCode =
19
21
  | typeof EXIT_SUCCESS
20
22
  | typeof EXIT_GENERIC_ERROR
@@ -32,6 +34,7 @@ export class ProcessManager {
32
34
  private shutdownHandlers: Set<ShutdownHandler> = new Set();
33
35
  private isShuttingDown = false;
34
36
  private exitCode: ExitCode = 0;
37
+ private logger = Logger.getInstance();
35
38
 
36
39
  private constructor() {
37
40
  this.setupSignalHandlers();
@@ -85,19 +88,23 @@ export class ProcessManager {
85
88
  }
86
89
 
87
90
  // Executa handlers em paralelo com timeout
91
+ this.logger.debug("Iniciando graceful shutdown...");
92
+
88
93
  const timeoutMs = TIMEOUT_SHUTDOWN_MS;
89
94
  const handlerPromises = Array.from(this.shutdownHandlers).map(async (handler) => {
90
95
  try {
91
96
  const timeoutPromise = new Promise((_, reject) =>
92
- setTimeout(() => reject(new Error('Shutdown handler timeout')), timeoutMs)
97
+ setTimeout(() => reject(new Error('Timeout do shutdown handler')), timeoutMs)
93
98
  );
94
99
  await Promise.race([handler(), timeoutPromise]);
95
100
  } catch (e) {
96
- console.error('Erro em shutdown handler:', e);
101
+ this.logger.error(`Erro em shutdown handler: ${(e as Error).message}`);
97
102
  }
98
103
  });
99
104
 
100
105
  await Promise.all(handlerPromises);
106
+
107
+ this.logger.debug(`Shutdown completo (exit code: ${this.exitCode})`);
101
108
 
102
109
  // Em ambiente de teste, não chama process.exit()
103
110
  if (process.env.NODE_ENV === 'test' || process.env.BUN_ENV === 'test') {
@@ -112,6 +119,8 @@ export class ProcessManager {
112
119
  * Use apenas em casos críticos onde não é seguro continuar.
113
120
  */
114
121
  exit(code: ExitCode): never {
122
+ this.logger.error(`Exit imediato solicitado (código: ${code})`);
123
+
115
124
  if (process.env.NODE_ENV === 'test' || process.env.BUN_ENV === 'test') {
116
125
  throw new ProcessExitError(code);
117
126
  }
@@ -119,16 +128,23 @@ export class ProcessManager {
119
128
  }
120
129
 
121
130
  private setupSignalHandlers(): void {
122
- process.on('SIGINT', () => this.shutdown(EXIT_SIGINT));
123
- process.on('SIGTERM', () => this.shutdown(0));
131
+ process.on('SIGINT', () => {
132
+ this.logger.debug("SIGINT recebido");
133
+ this.shutdown(EXIT_SIGINT);
134
+ });
135
+
136
+ process.on('SIGTERM', () => {
137
+ this.logger.debug("SIGTERM recebido");
138
+ this.shutdown(0);
139
+ });
124
140
 
125
141
  process.on('unhandledRejection', (reason, promise) => {
126
- console.error('Unhandled Rejection at:', promise, 'reason:', reason);
142
+ this.logger.error("Unhandled Rejection:", { reason: String(reason) });
127
143
  this.shutdown(1);
128
144
  });
129
145
 
130
146
  process.on('uncaughtException', (error) => {
131
- console.error('Uncaught Exception:', error);
147
+ this.logger.error("Uncaught Exception:", { message: error.message, stack: error.stack });
132
148
  this.shutdown(1);
133
149
  });
134
150
  }
@@ -139,7 +155,7 @@ export class ProcessManager {
139
155
  */
140
156
  export class ProcessExitError extends Error {
141
157
  constructor(public readonly code: ExitCode) {
142
- super(`Process exited with code ${code}`);
158
+ super(`Processo encerrou com código ${code}`);
143
159
  this.name = 'ProcessExitError';
144
160
  }
145
161
  }