@archznn/xavva 2.0.3 → 2.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.
- package/README.md +1 -78
- package/package.json +1 -1
- package/src/commands/AuditCommand.ts +3 -2
- package/src/commands/BuildCommand.ts +5 -3
- package/src/commands/CommandRegistry.ts +9 -5
- package/src/commands/DeployCommand.ts +36 -30
- package/src/commands/DepsCommand.ts +123 -0
- package/src/commands/DoctorCommand.ts +5 -4
- package/src/commands/HelpCommand.ts +94 -40
- package/src/commands/RunCommand.ts +13 -12
- package/src/commands/StartCommand.ts +5 -3
- package/src/index.ts +15 -5
- package/src/services/AuditService.ts +30 -4
- package/src/services/BuildCacheService.ts +2 -1
- package/src/services/BuildService.ts +8 -1
- package/src/services/DashboardService.ts +181 -118
- package/src/services/DependencyAnalyzerService.ts +538 -0
- package/src/services/ProjectService.ts +3 -3
- package/src/services/TomcatService.ts +11 -11
- package/src/services/WatcherService.ts +3 -2
- package/src/types/config.ts +4 -0
- package/src/utils/config.ts +7 -2
- package/src/utils/constants.ts +54 -0
- package/src/utils/processManager.ts +145 -0
- package/src/utils/ui.ts +237 -311
package/src/utils/ui.ts
CHANGED
|
@@ -1,315 +1,241 @@
|
|
|
1
1
|
import pkg from "../../package.json";
|
|
2
|
+
import type { DashboardService } from "../services/DashboardService";
|
|
3
|
+
|
|
4
|
+
// Paleta de cores moderna e minimalista
|
|
5
|
+
const C = {
|
|
6
|
+
reset: "\x1b[0m",
|
|
7
|
+
bold: "\x1b[1m",
|
|
8
|
+
dim: "\x1b[2m",
|
|
9
|
+
italic: "\x1b[3m",
|
|
10
|
+
|
|
11
|
+
// Cores principais
|
|
12
|
+
primary: "\x1b[36m", // Cyan
|
|
13
|
+
primaryBright: "\x1b[96m", // Bright Cyan
|
|
14
|
+
secondary: "\x1b[35m", // Magenta
|
|
15
|
+
|
|
16
|
+
// Estados
|
|
17
|
+
success: "\x1b[32m", // Green
|
|
18
|
+
successBright: "\x1b[92m", // Bright Green
|
|
19
|
+
warning: "\x1b[33m", // Yellow
|
|
20
|
+
warningBright: "\x1b[93m", // Bright Yellow
|
|
21
|
+
error: "\x1b[31m", // Red
|
|
22
|
+
errorBright: "\x1b[91m", // Bright Red
|
|
23
|
+
info: "\x1b[34m", // Blue
|
|
24
|
+
|
|
25
|
+
// Neutros
|
|
26
|
+
white: "\x1b[37m",
|
|
27
|
+
gray: "\x1b[90m",
|
|
28
|
+
lightGray: "\x1b[37m",
|
|
29
|
+
darkGray: "\x1b[38;5;240m",
|
|
30
|
+
};
|
|
2
31
|
|
|
3
32
|
export class Logger {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
if (deployMatch) {
|
|
213
|
-
this.domain("build");
|
|
214
|
-
return `${this.C.green}✔ Artifacts deployed`;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
const hotswapPattern = /HOTSWAP AGENT:.*? (INFO|WARN|ERROR|RELOAD) (.*?) - (.*)/;
|
|
218
|
-
const hotswapMatch = line.match(hotswapPattern);
|
|
219
|
-
if (hotswapMatch) {
|
|
220
|
-
const level = hotswapMatch[1];
|
|
221
|
-
let msg = hotswapMatch[3];
|
|
222
|
-
|
|
223
|
-
if (msg.includes("plugin initialized")) {
|
|
224
|
-
this.hotswapPluginsCount++;
|
|
225
|
-
return "";
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
if (msg.includes("redefinition") || msg.includes("reloaded") || level === 'RELOAD') {
|
|
229
|
-
if (msg.includes("Reloading classes [")) {
|
|
230
|
-
const classes = msg.match(/\[(.*?)\]/)?.[1] || "";
|
|
231
|
-
const classCount = classes.split(",").length;
|
|
232
|
-
if (classCount > 3) msg = `Reloading ${classCount} classes...`;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
if (msg === this.lastHotswapMsg) return "";
|
|
236
|
-
this.lastHotswapMsg = msg;
|
|
237
|
-
|
|
238
|
-
this.watcher(`Hotswap: ${msg.replace(/Class '.*?'/, (m) => this.C.bold + m + this.C.reset)}`, 'success');
|
|
239
|
-
return "";
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
if (msg.includes("Loading Hotswap agent")) {
|
|
243
|
-
this.domain("server");
|
|
244
|
-
return `${this.C.blue}▶ ${this.C.reset}Initializing Hotswap Agent ${msg.match(/\d+\.\d+\.\d+/)?.[0] || ""}`;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
if (this.hotswapPluginsCount > 0) {
|
|
248
|
-
const count = this.hotswapPluginsCount;
|
|
249
|
-
this.hotswapPluginsCount = 0;
|
|
250
|
-
this.domain("server");
|
|
251
|
-
this.write(` ${this.C.green}✔ ${this.C.reset}Hotswap ready (Plugins: ${count} loaded)`);
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
let color = this.C.cyan;
|
|
255
|
-
let symbol = "●";
|
|
256
|
-
if (level === "WARN") { color = this.C.yellow; symbol = "▲"; }
|
|
257
|
-
else if (level === "ERROR") { color = this.C.red; symbol = "✖"; }
|
|
258
|
-
|
|
259
|
-
this.domain("server");
|
|
260
|
-
return `${color}${symbol} ${this.C.bold}Hotswap:${this.C.reset} ${msg}`;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
if (line.includes("java.lang.UnsupportedOperationException") && (line.includes("add a method") || line.includes("change the schema"))) {
|
|
264
|
-
this.domain("watcher");
|
|
265
|
-
this.write(` ${this.C.red}✖ ${this.C.bold}Hotswap Falhou:${this.C.reset} Mudança estrutural detectada (novo método/campo).`);
|
|
266
|
-
this.write(` ${this.C.yellow}💡 Dica: Sua JVM atual não suporta mudar a estrutura da classe. Reinicie o servidor para aplicar.`);
|
|
267
|
-
return "";
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
const tomcatPattern = /^(\d{2}-\w{3}-\d{4} \d{2}:\d{2}:\d{2}\.\d{3})\s+(INFO|WARNING|SEVERE|ERROR)\s+\[(.*?)\]\s+(.*)$/;
|
|
271
|
-
const tMatch = line.match(tomcatPattern);
|
|
272
|
-
if (tMatch) {
|
|
273
|
-
const label = tMatch[2];
|
|
274
|
-
let msg = tMatch[4].trim();
|
|
275
|
-
if (this.isSystemNoise(msg)) return "";
|
|
276
|
-
let color = this.C.dim;
|
|
277
|
-
let symbol = "ℹ";
|
|
278
|
-
if (label === "WARNING") { color = this.C.yellow; symbol = "▲"; }
|
|
279
|
-
else if (label === "SEVERE" || label === "ERROR") { color = this.C.red; symbol = "✖"; }
|
|
280
|
-
msg = msg.replace(/^(org\.apache|com\.sun|java\..*?|org\.glassfish)\.[a-zA-Z0-9.]+\s/, "").trim();
|
|
281
|
-
if (!msg) return "";
|
|
282
|
-
return `${color}${symbol} ${msg}`;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
const compilationErrorMatch = line.match(/^\[ERROR\]\s+(.*\.java):\[(\d+),(\d+)\]\s+(.*)$/);
|
|
286
|
-
if (compilationErrorMatch) {
|
|
287
|
-
const [_, filePath, row, col, msg] = compilationErrorMatch;
|
|
288
|
-
const fileName = filePath.split(/[/\\]/).pop();
|
|
289
|
-
return `${this.C.red}✖ ERROR ${this.C.reset}${this.C.dim}em ${this.C.reset}${this.C.bold}${fileName}${this.C.reset}${this.C.dim}:${row}${this.C.reset} ${this.C.red}➜ ${this.C.reset}${msg}`;
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
const logPattern = /^\[(INFO|WARNING|WARN|SEVERE|ERROR)\]\s+(.*)$/;
|
|
293
|
-
const match = line.match(logPattern);
|
|
294
|
-
if (match) {
|
|
295
|
-
const label = match[1];
|
|
296
|
-
let msg = match[2].trim();
|
|
297
|
-
if (msg.includes("Total time:") || msg.includes("Finished at:") || msg.includes("Final Memory:") || msg.includes("-----------------------")) return "";
|
|
298
|
-
let color = this.C.dim;
|
|
299
|
-
let symbol = "ℹ";
|
|
300
|
-
if (label === "WARNING") { color = this.C.yellow; symbol = "▲"; }
|
|
301
|
-
else if (label === "SEVERE" || label === "ERROR") { color = this.C.red; symbol = "✖"; }
|
|
302
|
-
msg = msg.replace(/^(org\.apache|com\.sun|java\..*?)\.[a-zA-Z0-9.]+\s/, "").trim();
|
|
303
|
-
if (!msg || msg === "]" || msg.includes("Compilation failure")) return "";
|
|
304
|
-
return `${color}${symbol} ${msg}`;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
if (line.includes("Exception") || line.includes("Caused by") || line.includes("at ")) {
|
|
308
|
-
const trimmed = line.trim();
|
|
309
|
-
const color = (trimmed.includes("org.apache") || trimmed.includes("java.base") || trimmed.includes("sun.reflect")) ? this.C.dim : this.C.yellow;
|
|
310
|
-
return ` ${color}${trimmed}`;
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
return "";
|
|
314
|
-
}
|
|
33
|
+
public static readonly C = C;
|
|
34
|
+
private static dashboard: DashboardService | null = null;
|
|
35
|
+
private static activeSpinner: { stop: (success?: boolean) => void } | null = null;
|
|
36
|
+
private static lastDomain = "";
|
|
37
|
+
|
|
38
|
+
static setDashboard(dashboard: DashboardService) {
|
|
39
|
+
this.dashboard = dashboard;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Banner moderno e clean
|
|
43
|
+
static banner(command?: string, profile?: string, encoding?: string) {
|
|
44
|
+
console.clear();
|
|
45
|
+
const git = this.getGitContext();
|
|
46
|
+
const name = process.cwd().split(/[/\\]/).pop() || "project";
|
|
47
|
+
|
|
48
|
+
// Linha superior decorativa
|
|
49
|
+
console.log(`${C.gray}┌────────────────────────────────────────────────────────┐${C.reset}`);
|
|
50
|
+
|
|
51
|
+
// Logo e projeto
|
|
52
|
+
console.log(`${C.gray}│${C.reset} ${C.primary}${C.bold}XAVVA${C.reset}${C.gray}.${C.reset}${C.dim}v${pkg.version}${C.reset} ${C.gray}│${C.reset} ${C.white}${C.bold}${name}${C.reset}`);
|
|
53
|
+
|
|
54
|
+
// Info adicional em uma linha
|
|
55
|
+
const parts: string[] = [];
|
|
56
|
+
if (command) parts.push(`${C.primary}${command}${C.reset}`);
|
|
57
|
+
if (profile) parts.push(`${C.warning}profile:${profile}${C.reset}`);
|
|
58
|
+
if (encoding) parts.push(`${C.info}${encoding}${C.reset}`);
|
|
59
|
+
if (git.branch) parts.push(`${C.secondary}git:${git.branch}${C.reset}`);
|
|
60
|
+
|
|
61
|
+
if (parts.length > 0) {
|
|
62
|
+
console.log(`${C.gray}│${C.reset} ${C.dim}mode${C.reset} ${C.gray}│${C.reset} ${parts.join(` ${C.gray}•${C.reset} `)}`);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Linha inferior
|
|
66
|
+
console.log(`${C.gray}└────────────────────────────────────────────────────────┘${C.reset}`);
|
|
67
|
+
console.log();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Seções com divisórias clean
|
|
71
|
+
static section(title: string) {
|
|
72
|
+
console.log(`${C.gray}┌─ ${C.white}${C.bold}${title}${C.reset}`);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
static endSection() {
|
|
76
|
+
console.log(`${C.gray}└${C.reset}`);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Configurações em formato chave: valor alinhado
|
|
80
|
+
static config(label: string, value: string | number | boolean) {
|
|
81
|
+
const valueStr = String(value);
|
|
82
|
+
const isBool = typeof value === 'boolean';
|
|
83
|
+
const displayValue = isBool
|
|
84
|
+
? (value ? `${C.successBright}✓${C.reset} ${C.success}enabled${C.reset}` : `${C.gray}○${C.reset} ${C.gray}disabled${C.reset}`)
|
|
85
|
+
: `${C.white}${valueStr}${C.reset}`;
|
|
86
|
+
|
|
87
|
+
console.log(`${C.gray}│${C.reset} ${C.dim}${label.padEnd(12)}${C.reset} ${C.gray}:${C.reset} ${displayValue}`);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Status com ícones minimalistas
|
|
91
|
+
static ready(msg: string) {
|
|
92
|
+
console.log(`${C.gray}│${C.reset} ${C.success}●${C.reset} ${msg}`);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
static info(label: string, value?: string) {
|
|
96
|
+
if (value) {
|
|
97
|
+
console.log(`${C.gray}│${C.reset} ${C.dim}${label}${C.reset} ${C.gray}:${C.reset} ${C.white}${value}${C.reset}`);
|
|
98
|
+
} else {
|
|
99
|
+
console.log(`${C.gray}│${C.reset} ${C.info}ℹ${C.reset} ${label}`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
static success(msg: string) {
|
|
104
|
+
console.log(`${C.gray}│${C.reset} ${C.success}✓${C.reset} ${msg}`);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
static error(msg: string) {
|
|
108
|
+
console.log(`${C.gray}│${C.reset} ${C.error}✗${C.reset} ${C.error}${msg}${C.reset}`);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
static warn(msg: string) {
|
|
112
|
+
console.log(`${C.gray}│${C.reset} ${C.warning}⚠${C.reset} ${msg}`);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
static build(msg: string) {
|
|
116
|
+
console.log(`${C.gray}│${C.reset} ${C.primary}▸${C.reset} ${C.dim}build${C.reset} ${C.gray}:${C.reset} ${msg}`);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
static server(msg: string) {
|
|
120
|
+
console.log(`${C.gray}│${C.reset} ${C.primary}▸${C.reset} ${C.dim}server${C.reset} ${C.gray}:${C.reset} ${msg}`);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
static watch(msg: string) {
|
|
124
|
+
console.log(`${C.gray}│${C.reset} ${C.secondary}◉${C.reset} ${C.dim}watch${C.reset} ${C.gray}:${C.reset} ${msg}`);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
static hotswap(msg: string) {
|
|
128
|
+
console.log(`${C.gray}│${C.reset} ${C.secondary}↻${C.reset} ${C.dim}hotswap${C.reset} ${C.gray}:${C.reset} ${msg}`);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// URL formatada de forma destacada
|
|
132
|
+
static url(label: string, url: string) {
|
|
133
|
+
console.log(`${C.gray}│${C.reset} ${C.dim}${label}${C.reset} ${C.gray}:${C.reset} ${C.primaryBright}${C.bold}${url}${C.reset}`);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Spinner moderno
|
|
137
|
+
static spinner(msg: string) {
|
|
138
|
+
if (this.dashboard?.isTuiActive()) {
|
|
139
|
+
return this.dashboard.spinner(msg);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
143
|
+
let i = 0;
|
|
144
|
+
|
|
145
|
+
process.stdout.write(`${C.gray}│${C.reset} `);
|
|
146
|
+
process.stdout.write("\x1B[?25l");
|
|
147
|
+
|
|
148
|
+
const timer = setInterval(() => {
|
|
149
|
+
process.stdout.write(`\r${C.gray}│${C.reset} ${C.primary}${frames[i]}${C.reset} ${C.dim}${msg}${C.reset}`);
|
|
150
|
+
i = (i + 1) % frames.length;
|
|
151
|
+
}, 80);
|
|
152
|
+
|
|
153
|
+
return (success = true) => {
|
|
154
|
+
clearInterval(timer);
|
|
155
|
+
process.stdout.write("\x1B[?25h");
|
|
156
|
+
if (success) {
|
|
157
|
+
console.log(`\r${C.gray}│${C.reset} ${C.success}✓${C.reset} ${msg}`);
|
|
158
|
+
} else {
|
|
159
|
+
console.log(`\r${C.gray}│${C.reset} ${C.error}✗${C.reset} ${C.error}${msg}${C.reset}`);
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Linha em branco
|
|
165
|
+
static newline() {
|
|
166
|
+
console.log();
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Divisória simples
|
|
170
|
+
static divider() {
|
|
171
|
+
console.log(`${C.gray}├────────────────────────────────────────────────────────┤${C.reset}`);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Finalização
|
|
175
|
+
static done() {
|
|
176
|
+
console.log(`${C.gray}└────────────────────────────────────────────────────────┘${C.reset}`);
|
|
177
|
+
console.log();
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Helper para contexto git
|
|
181
|
+
static getGitContext(): { branch: string; author: string; hash: string } {
|
|
182
|
+
try {
|
|
183
|
+
const branch = Bun.spawnSync(["git", "rev-parse", "abbrev-ref", "HEAD"]).stdout.toString().trim();
|
|
184
|
+
const author = Bun.spawnSync(["git", "log", "-1", "format=%an"]).stdout.toString().trim();
|
|
185
|
+
const hash = Bun.spawnSync(["git", "rev-parse", "--short", "HEAD"]).stdout.toString().trim();
|
|
186
|
+
return { branch, author, hash };
|
|
187
|
+
} catch {
|
|
188
|
+
return { branch: "", author: "", hash: "" };
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Filtros de noise (mantidos)
|
|
193
|
+
static isSystemNoise(line: string): boolean {
|
|
194
|
+
const noise = [
|
|
195
|
+
"Using CATALINA_", "Using JRE_HOME", "Using CLASSPATH",
|
|
196
|
+
"Scanning for projects...", "Building ", "--- ", "+++ ",
|
|
197
|
+
"Arquivos processados em", "milliseconds",
|
|
198
|
+
"SLF4J: ", "Discovered plugins:",
|
|
199
|
+
"enhanced with plugin initialization", "Hotswap ready",
|
|
200
|
+
"autoHotswap.delay", "watchResources=false",
|
|
201
|
+
];
|
|
202
|
+
return noise.some(n => line.includes(n));
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Sumarização de logs do Tomcat (simplificada)
|
|
206
|
+
static summarize(line: string): string {
|
|
207
|
+
if (this.isSystemNoise(line)) return "";
|
|
208
|
+
|
|
209
|
+
// Server startup
|
|
210
|
+
const startupMatch = line.match(/Server startup in.*?([\d,]+)\s*ms/);
|
|
211
|
+
if (startupMatch) {
|
|
212
|
+
const time = startupMatch[1].replace(",", "");
|
|
213
|
+
const seconds = (parseInt(time) / 1000).toFixed(1);
|
|
214
|
+
return `${C.success}ready ${C.gray}in ${C.white}${seconds}s${C.reset}`;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Hotswap
|
|
218
|
+
if (line.includes("HOTSWAP AGENT") && line.includes("RELOAD")) {
|
|
219
|
+
return `${C.secondary}↻ hotswap ${C.gray}detected${C.reset}`;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Erros de compilação
|
|
223
|
+
const compilationError = line.match(/\[ERROR\].*?(\w+\.java):\[(\d+).*?\]\s*(.+)/);
|
|
224
|
+
if (compilationError) {
|
|
225
|
+
const [, file, lineNum, msg] = compilationError;
|
|
226
|
+
return `${C.error}✗ ${C.white}${file}${C.gray}:${lineNum}${C.reset} ${C.gray}${msg.slice(0, 50)}${C.reset}`;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Erros SEVERE
|
|
230
|
+
if (line.includes("SEVERE") || line.includes("Exception")) {
|
|
231
|
+
return `${C.error}✗ ${C.gray}${line.slice(0, 80)}${C.reset}`;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Warnings
|
|
235
|
+
if (line.includes("WARNING")) {
|
|
236
|
+
return `${C.warning}⚠ ${C.gray}${line.slice(0, 80)}${C.reset}`;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return "";
|
|
240
|
+
}
|
|
315
241
|
}
|