@archznn/xavva 3.1.3 → 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 +33 -31
  9. package/src/commands/DeployCommand.ts +252 -229
  10. package/src/commands/DepsCommand.ts +174 -174
  11. package/src/commands/DockerCommand.ts +14 -14
  12. package/src/commands/DoctorCommand.ts +252 -239
  13. package/src/commands/EncodingCommand.ts +19 -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 +6 -6
  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 +4 -4
  26. package/src/commands/TomcatCommand.ts +219 -100
  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 +11 -3
  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,242 @@
1
+ /**
2
+ * Comando Clean - Limpa cache, builds e logs
3
+ *
4
+ * Uso:
5
+ * xavva clean # limpa tudo
6
+ * xavva clean --cache # só cache
7
+ * xavva clean --build # só target/build
8
+ * xavva clean --logs # só logs do Tomcat
9
+ * xavva clean --tomcat # só work do Tomcat
10
+ */
11
+
12
+ import { rm, readdir } from "fs/promises";
13
+ import { existsSync } from "fs";
14
+ import path from "path";
15
+ import os from "os";
16
+ import type { Command } from "./Command";
17
+ import type { AppConfig, CLIArguments } from "../types/config";
18
+ import { Logger } from "../logging";
19
+ import { PATHS } from "../config/versions";
20
+
21
+ interface CleanOptions {
22
+ all: boolean;
23
+ cache: boolean;
24
+ build: boolean;
25
+ logs: boolean;
26
+ tomcat: boolean;
27
+ }
28
+
29
+ interface CleanResult {
30
+ cleaned: string[];
31
+ failed: Array<{ path: string; error: string }>;
32
+ bytesFreed: number;
33
+ }
34
+
35
+ export class CleanCommand implements Command {
36
+ private logger = Logger.getInstance();
37
+
38
+ async execute(config: AppConfig, args: CLIArguments): Promise<void> {
39
+ const options = this.parseOptions(args);
40
+
41
+ this.logger.section("LIMPEZA");
42
+
43
+ const result: CleanResult = {
44
+ cleaned: [],
45
+ failed: [],
46
+ bytesFreed: 0,
47
+ };
48
+
49
+ // Limpa cache
50
+ if (options.cache || options.all) {
51
+ await this.cleanCache(result);
52
+ }
53
+
54
+ // Limpa build
55
+ if (options.build || options.all) {
56
+ await this.cleanBuild(result, config);
57
+ }
58
+
59
+ // Limpa logs
60
+ if (options.logs || options.all) {
61
+ await this.cleanLogs(result, config);
62
+ }
63
+
64
+ // Limpa Tomcat work
65
+ if (options.tomcat || options.all) {
66
+ await this.cleanTomcatWork(result, config);
67
+ }
68
+
69
+ this.printSummary(result);
70
+ }
71
+
72
+ private parseOptions(args: CLIArguments): CleanOptions {
73
+ const hasSpecific = args.cache || args.build || args.logs || (args as any).tomcat;
74
+
75
+ return {
76
+ all: !hasSpecific, // Se nenhum específico, limpa tudo
77
+ cache: !!(args.cache || !hasSpecific),
78
+ build: !!(args.build || !hasSpecific),
79
+ logs: !!(args.logs || !hasSpecific),
80
+ tomcat: !!((args as any).tomcat || !hasSpecific),
81
+ };
82
+ }
83
+
84
+ private async cleanCache(result: CleanResult): Promise<void> {
85
+ this.logger.step("Limpando cache...");
86
+
87
+ const cacheDirs = [
88
+ path.join(os.homedir(), '.xavva', 'cache'),
89
+ path.join(os.homedir(), '.xavva', 'dependency-cache'),
90
+ path.join(os.homedir(), '.xavva', 'build-cache'),
91
+ path.join(process.cwd(), PATHS.XAVVA_DIR, 'cache'),
92
+ ];
93
+
94
+ for (const dir of cacheDirs) {
95
+ if (existsSync(dir)) {
96
+ try {
97
+ const size = await this.getDirectorySize(dir);
98
+ await rm(dir, { recursive: true, force: true });
99
+ result.cleaned.push(`cache: ${path.basename(dir)}`);
100
+ result.bytesFreed += size;
101
+ } catch (e) {
102
+ result.failed.push({ path: dir, error: (e as Error).message });
103
+ }
104
+ }
105
+ }
106
+ }
107
+
108
+ private async cleanBuild(result: CleanResult, config: AppConfig): Promise<void> {
109
+ this.logger.step("Limpando diretórios de build...");
110
+
111
+ const buildDirs = [
112
+ path.join(process.cwd(), PATHS.TARGET_DIR),
113
+ path.join(process.cwd(), PATHS.BUILD_DIR),
114
+ ];
115
+
116
+ for (const dir of buildDirs) {
117
+ if (existsSync(dir)) {
118
+ try {
119
+ const size = await this.getDirectorySize(dir);
120
+ await rm(dir, { recursive: true, force: true });
121
+ result.cleaned.push(`build: ${path.basename(dir)}`);
122
+ result.bytesFreed += size;
123
+ } catch (e) {
124
+ result.failed.push({ path: dir, error: (e as Error).message });
125
+ }
126
+ }
127
+ }
128
+ }
129
+
130
+ private async cleanLogs(result: CleanResult, config: AppConfig): Promise<void> {
131
+ this.logger.step("Limpando logs...");
132
+
133
+ const logDirs = [
134
+ path.join(config.tomcat.path, "logs"),
135
+ path.join(process.cwd(), PATHS.XAVVA_DIR, "logs"),
136
+ ];
137
+
138
+ for (const dir of logDirs) {
139
+ if (existsSync(dir)) {
140
+ try {
141
+ const files = await readdir(dir);
142
+ let dirSize = 0;
143
+
144
+ for (const file of files) {
145
+ if (file.endsWith('.log') || file.endsWith('.txt')) {
146
+ const filePath = path.join(dir, file);
147
+ const stats = await Bun.file(filePath).stat();
148
+ dirSize += stats.size;
149
+ await rm(filePath);
150
+ }
151
+ }
152
+
153
+ result.cleaned.push(`logs: ${path.basename(dir)} (${files.length} arquivos)`);
154
+ result.bytesFreed += dirSize;
155
+ } catch (e) {
156
+ result.failed.push({ path: dir, error: (e as Error).message });
157
+ }
158
+ }
159
+ }
160
+ }
161
+
162
+ private async cleanTomcatWork(result: CleanResult, config: AppConfig): Promise<void> {
163
+ this.logger.step("Limpando work do Tomcat...");
164
+
165
+ const workDirs = [
166
+ path.join(config.tomcat.path, "work"),
167
+ path.join(config.tomcat.path, "temp"),
168
+ path.join(config.tomcat.path, PATHS.WEBAPP_DIR),
169
+ ];
170
+
171
+ for (const dir of workDirs) {
172
+ if (existsSync(dir)) {
173
+ try {
174
+ const size = await this.getDirectorySize(dir);
175
+ await rm(dir, { recursive: true, force: true });
176
+ result.cleaned.push(`tomcat: ${path.basename(dir)}`);
177
+ result.bytesFreed += size;
178
+ } catch (e) {
179
+ result.failed.push({ path: dir, error: (e as Error).message });
180
+ }
181
+ }
182
+ }
183
+ }
184
+
185
+ private async getDirectorySize(dir: string): Promise<number> {
186
+ let total = 0;
187
+
188
+ try {
189
+ const files = await readdir(dir, { withFileTypes: true });
190
+
191
+ for (const file of files) {
192
+ const filePath = path.join(dir, file.name);
193
+
194
+ if (file.isDirectory()) {
195
+ total += await this.getDirectorySize(filePath);
196
+ } else {
197
+ const stats = await Bun.file(filePath).stat();
198
+ total += stats.size;
199
+ }
200
+ }
201
+ } catch {
202
+ // Ignora erros
203
+ }
204
+
205
+ return total;
206
+ }
207
+
208
+ private formatBytes(bytes: number): string {
209
+ if (bytes === 0) return "0 B";
210
+
211
+ const units = ["B", "KB", "MB", "GB"];
212
+ const i = Math.floor(Math.log(bytes) / Math.log(1024));
213
+
214
+ return `${(bytes / Math.pow(1024, i)).toFixed(2)} ${units[i]}`;
215
+ }
216
+
217
+ private printSummary(result: CleanResult): void {
218
+ this.logger.newline();
219
+ this.logger.divider();
220
+
221
+ if (result.cleaned.length > 0) {
222
+ this.logger.success(`${result.cleaned.length} item(ns) limpo(s)`);
223
+ for (const item of result.cleaned) {
224
+ this.logger.info(` ✓ ${item}`);
225
+ }
226
+ }
227
+
228
+ if (result.failed.length > 0) {
229
+ this.logger.warn(`${result.failed.length} falha(s)`);
230
+ for (const item of result.failed) {
231
+ this.logger.error(` ✗ ${path.basename(item.path)}: ${item.error}`);
232
+ }
233
+ }
234
+
235
+ this.logger.divider();
236
+ this.logger.info(`Espaço liberado: ${this.formatBytes(result.bytesFreed)}`);
237
+
238
+ if (result.cleaned.length === 0 && result.failed.length === 0) {
239
+ this.logger.info("Nada para limpar - já está tudo organizado!");
240
+ }
241
+ }
242
+ }
@@ -1,6 +1,6 @@
1
1
  import type { Command } from "./Command";
2
2
  import type { AppConfig, CLIArguments } from "../types/config";
3
- import { Logger } from "../utils/ui";
3
+ import { Logger, C } from "../utils/ui";
4
4
 
5
5
  export class CompletionCommand implements Command {
6
6
  private readonly commands = [
@@ -51,14 +51,14 @@ export class CompletionCommand implements Command {
51
51
  Logger.section("Shell Completion");
52
52
  Logger.info("Uso: xavva completion <shell>");
53
53
  Logger.newline();
54
- Logger.log(`${Logger.C.gray}│${Logger.C.reset} ${Logger.C.primary}xavva completion bash${Logger.C.reset} ${Logger.C.gray}# Bash${Logger.C.reset}`);
55
- Logger.log(`${Logger.C.gray}│${Logger.C.reset} ${Logger.C.primary}xavva completion zsh${Logger.C.reset} ${Logger.C.gray}# Zsh${Logger.C.reset}`);
56
- Logger.log(`${Logger.C.gray}│${Logger.C.reset} ${Logger.C.primary}xavva completion fish${Logger.C.reset} ${Logger.C.gray}# Fish${Logger.C.reset}`);
54
+ Logger.log(`${C.gray}│${C.reset} ${C.primary}xavva completion bash${C.reset} ${C.gray}# Bash${C.reset}`);
55
+ Logger.log(`${C.gray}│${C.reset} ${C.primary}xavva completion zsh${C.reset} ${C.gray}# Zsh${C.reset}`);
56
+ Logger.log(`${C.gray}│${C.reset} ${C.primary}xavva completion fish${C.reset} ${C.gray}# Fish${C.reset}`);
57
57
  Logger.endSection();
58
58
  Logger.dim("Adicione ao seu shell:");
59
- Logger.log(` ${Logger.C.gray}# Bash: echo 'eval "$(xavva completion bash)"' >> ~/.bashrc${Logger.C.reset}`);
60
- Logger.log(` ${Logger.C.gray}# Zsh: echo 'eval "$(xavva completion zsh)"' >> ~/.zshrc${Logger.C.reset}`);
61
- Logger.log(` ${Logger.C.gray}# Fish: xavva completion fish > ~/.config/fish/completions/xavva.fish${Logger.C.reset}`);
59
+ Logger.log(` ${C.gray}# Bash: echo 'eval "$(xavva completion bash)"' >> ~/.bashrc${C.reset}`);
60
+ Logger.log(` ${C.gray}# Zsh: echo 'eval "$(xavva completion zsh)"' >> ~/.zshrc${C.reset}`);
61
+ Logger.log(` ${C.gray}# Fish: xavva completion fish > ~/.config/fish/completions/xavva.fish${C.reset}`);
62
62
  }
63
63
  }
64
64
 
@@ -6,28 +6,30 @@
6
6
  import type { Command } from "./Command";
7
7
  import type { AppConfig, CLIArguments } from "../types/config";
8
8
  import { DbService, type DbConfig } from "../services/DbService";
9
- import { Logger } from "../utils/ui";
9
+ import { Logger } from "../logging";
10
10
  import { ProcessManager } from "../utils/processManager";
11
11
 
12
12
  export class DbCommand implements Command {
13
+ private logger = Logger.getInstance();
14
+
13
15
  private showHelp(): void {
14
- Logger.section("Database Command");
15
- Logger.log(`${Logger.C.bold}Usage:${Logger.C.reset} xavva db <action> [options]`);
16
- Logger.newline();
17
- Logger.log(`${Logger.C.bold}Actions:${Logger.C.reset}`);
18
- Logger.log(` ${Logger.C.primary}status${Logger.C.reset} Show migration status`);
19
- Logger.log(` ${Logger.C.primary}migrate${Logger.C.reset} Run pending migrations`);
20
- Logger.log(` ${Logger.C.primary}reset${Logger.C.reset} Reset database (⚠️ destructive)`);
21
- Logger.log(` ${Logger.C.primary}seed${Logger.C.reset} Populate with test data`);
22
- Logger.newline();
23
- Logger.log(`${Logger.C.bold}Options:${Logger.C.reset}`);
24
- Logger.log(` --force Confirm destructive operations`);
25
- Logger.log(` --env <name> Use environment config`);
26
- Logger.newline();
27
- Logger.log(`${Logger.C.bold}Examples:${Logger.C.reset}`);
28
- Logger.log(` xavva db status`);
29
- Logger.log(` xavva db migrate`);
30
- Logger.log(` xavva db reset --force`);
16
+ this.logger.section("Database Command");
17
+ console.log(`Usage: xavva db <action> [options]`);
18
+ this.logger.newline();
19
+ console.log(`Actions:`);
20
+ console.log(` status Show migration status`);
21
+ console.log(` migrate Run pending migrations`);
22
+ console.log(` reset Reset database (! destructive)`);
23
+ console.log(` seed Populate with test data`);
24
+ this.logger.newline();
25
+ console.log(`Options:`);
26
+ console.log(` --force Confirm destructive operations`);
27
+ console.log(` --env <name> Use environment config`);
28
+ this.logger.newline();
29
+ console.log(`Examples:`);
30
+ console.log(` xavva db status`);
31
+ console.log(` xavva db migrate`);
32
+ console.log(` xavva db reset --force`);
31
33
  }
32
34
 
33
35
  async execute(config: AppConfig, args?: CLIArguments, positionals?: string[]): Promise<void> {
@@ -52,7 +54,7 @@ export class DbCommand implements Command {
52
54
  case "up":
53
55
  const migrateResult = await service.migrate(dbConfig);
54
56
  if (!migrateResult.success) {
55
- Logger.error(migrateResult.message);
57
+ this.logger.error(migrateResult.message);
56
58
  await processManager.shutdown(1);
57
59
  }
58
60
  break;
@@ -66,8 +68,8 @@ export class DbCommand implements Command {
66
68
  case "clean":
67
69
  case "drop":
68
70
  if (!args?.force) {
69
- Logger.warn("This will DELETE all data in the database!");
70
- Logger.info("Use", "--force to confirm");
71
+ this.logger.warn("This will DELETE all data in the database!");
72
+ this.logger.info("Use --force to confirm");
71
73
  await processManager.shutdown(1);
72
74
  return;
73
75
  }
@@ -82,7 +84,7 @@ export class DbCommand implements Command {
82
84
  case "seed":
83
85
  const seedResult = await service.seed(dbConfig, args?.src);
84
86
  if (!seedResult.success) {
85
- Logger.error(seedResult.message);
87
+ this.logger.error(seedResult.message);
86
88
  await processManager.shutdown(1);
87
89
  }
88
90
  break;
@@ -92,12 +94,12 @@ export class DbCommand implements Command {
92
94
  break;
93
95
 
94
96
  default:
95
- Logger.error(`Unknown db action: ${action}`);
96
- Logger.info("Actions", "migrate, status, reset, seed, create");
97
+ this.logger.error(`Unknown db action: ${action}`);
98
+ this.logger.info("Actions: migrate, status, reset, seed, create");
97
99
  await processManager.shutdown(1);
98
100
  }
99
101
  } catch (error) {
100
- Logger.error(`Database command failed: ${(error as Error).message}`);
102
+ this.logger.error(`Database command failed: ${(error as Error).message}`);
101
103
  await processManager.shutdown(1);
102
104
  }
103
105
  }
@@ -130,8 +132,8 @@ export class DbCommand implements Command {
130
132
 
131
133
  private async createMigration(service: DbService, args?: CLIArguments): Promise<void> {
132
134
  const name = args?.name || "new_migration";
133
- Logger.section("Create Migration");
134
- Logger.info("Name", name);
135
+ this.logger.section("Create Migration");
136
+ this.logger.config("Name", name);
135
137
 
136
138
  // Detecta ferramenta
137
139
  const tool = await service.detectTool();
@@ -141,13 +143,13 @@ export class DbCommand implements Command {
141
143
  const filename = `V${timestamp}__${name}.sql`;
142
144
  const filepath = `src/main/resources/db/migration/${filename}`;
143
145
 
144
- Logger.success(`Create file: ${filepath}`);
145
- Logger.dim("-- Add your SQL here");
146
+ this.logger.success(`Create file: ${filepath}`);
147
+ console.log("-- Add your SQL here");
146
148
  } else if (tool === "liquibase") {
147
149
  const filename = `${name}.sql`;
148
- Logger.success(`Add to changelog: db/changelog/${filename}`);
150
+ this.logger.success(`Add to changelog: db/changelog/${filename}`);
149
151
  } else {
150
- Logger.warn("No migration tool detected");
152
+ this.logger.warn("No migration tool detected");
151
153
  }
152
154
  }
153
155
  }