@archznn/xavva 2.6.0 → 2.8.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 +55 -0
- package/package.json +4 -2
- package/src/commands/CompletionCommand.ts +212 -0
- package/src/commands/ConfigCommand.ts +184 -0
- package/src/commands/DeployCommand.ts +2 -1
- package/src/commands/EncodingCommand.ts +351 -0
- package/src/commands/HealthCommand.ts +302 -0
- package/src/commands/HelpCommand.ts +42 -0
- package/src/commands/HistoryCommand.ts +49 -0
- package/src/commands/InitCommand.ts +148 -0
- package/src/commands/RedoCommand.ts +36 -0
- package/src/config/versions.ts +63 -0
- package/src/di/container.ts +249 -0
- package/src/errors/ErrorHandler.ts +249 -0
- package/src/errors/XavvaError.ts +273 -0
- package/src/index.ts +136 -96
- package/src/services/AuditService.ts +3 -2
- package/src/services/BrowserService.ts +127 -16
- package/src/services/DeployWatcher.ts +183 -0
- package/src/services/EmbeddedTomcatService.ts +67 -37
- package/src/services/EncodingService.ts +548 -0
- package/src/services/FileWatcher.ts +243 -0
- package/src/services/HistoryService.ts +73 -0
- package/src/services/NotificationService.ts +145 -0
- package/src/services/TomcatService.ts +59 -26
- package/src/types/args.ts +151 -0
- package/src/types/config.ts +6 -0
- package/src/types/index.ts +7 -0
- package/src/utils/PathUtils.ts +221 -0
- package/src/utils/ProgressBar.ts +182 -0
- package/src/utils/config.ts +6 -0
- package/src/utils/parsers/JavaParser.ts +413 -0
- package/src/utils/platform.ts +2 -2
- package/src/services/WatcherService.ts +0 -117
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ErrorHandler centralizado
|
|
3
|
+
* Trata todos os erros do aplicativo de forma uniforme
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
XavvaError,
|
|
8
|
+
isOperationalError,
|
|
9
|
+
getExitCode,
|
|
10
|
+
NetworkError,
|
|
11
|
+
FileSystemError,
|
|
12
|
+
BuildError,
|
|
13
|
+
TomcatError,
|
|
14
|
+
ConfigError
|
|
15
|
+
} from "./XavvaError";
|
|
16
|
+
import { Logger } from "../utils/ui";
|
|
17
|
+
import { ProcessManager } from "../utils/processManager";
|
|
18
|
+
|
|
19
|
+
export interface ErrorReport {
|
|
20
|
+
error: Error;
|
|
21
|
+
code: string;
|
|
22
|
+
exitCode: number;
|
|
23
|
+
isOperational: boolean;
|
|
24
|
+
context?: Record<string, unknown>;
|
|
25
|
+
timestamp: Date;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export class ErrorHandler {
|
|
29
|
+
private static instance: ErrorHandler;
|
|
30
|
+
private errorHistory: ErrorReport[] = [];
|
|
31
|
+
private maxHistorySize = 10;
|
|
32
|
+
private isShuttingDown = false;
|
|
33
|
+
|
|
34
|
+
private constructor() {}
|
|
35
|
+
|
|
36
|
+
static getInstance(): ErrorHandler {
|
|
37
|
+
if (!ErrorHandler.instance) {
|
|
38
|
+
ErrorHandler.instance = new ErrorHandler();
|
|
39
|
+
}
|
|
40
|
+
return ErrorHandler.instance;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Trata qualquer erro de forma apropriada
|
|
45
|
+
*/
|
|
46
|
+
async handle(error: unknown, context?: Record<string, unknown>): Promise<void> {
|
|
47
|
+
if (this.isShuttingDown) return;
|
|
48
|
+
|
|
49
|
+
const normalizedError = this.normalizeError(error);
|
|
50
|
+
const report = this.createReport(normalizedError, context);
|
|
51
|
+
|
|
52
|
+
// Adiciona ao histórico
|
|
53
|
+
this.addToHistory(report);
|
|
54
|
+
|
|
55
|
+
// Log apropriado baseado no tipo de erro
|
|
56
|
+
if (normalizedError instanceof XavvaError) {
|
|
57
|
+
this.handleXavvaError(normalizedError);
|
|
58
|
+
} else {
|
|
59
|
+
this.handleUnexpectedError(normalizedError);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Se não for erro operacional, mostra stack trace em verbose
|
|
63
|
+
if (!report.isOperational) {
|
|
64
|
+
Logger.debug("Stack trace:");
|
|
65
|
+
Logger.debug(normalizedError.stack || "N/A");
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Shutdown com código apropriado
|
|
69
|
+
const processManager = ProcessManager.getInstance();
|
|
70
|
+
await processManager.shutdown(report.exitCode);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Trata erro sem fazer shutdown (para operações que podem continuar)
|
|
75
|
+
*/
|
|
76
|
+
handleGraceful(error: unknown, context?: Record<string, unknown>): ErrorReport {
|
|
77
|
+
const normalizedError = this.normalizeError(error);
|
|
78
|
+
const report = this.createReport(normalizedError, context);
|
|
79
|
+
|
|
80
|
+
this.addToHistory(report);
|
|
81
|
+
|
|
82
|
+
if (normalizedError instanceof XavvaError) {
|
|
83
|
+
this.logXavvaError(normalizedError, false);
|
|
84
|
+
} else {
|
|
85
|
+
Logger.warn(`Erro inesperado: ${normalizedError.message}`);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return report;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Normaliza qualquer valor para Error
|
|
93
|
+
*/
|
|
94
|
+
private normalizeError(error: unknown): Error {
|
|
95
|
+
if (error instanceof Error) {
|
|
96
|
+
return error;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (typeof error === "string") {
|
|
100
|
+
return new Error(error);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (error && typeof error === "object" && "message" in error) {
|
|
104
|
+
return new Error(String((error as { message: unknown }).message));
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return new Error("Erro desconhecido");
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Cria um relatório de erro estruturado
|
|
112
|
+
*/
|
|
113
|
+
private createReport(error: Error, context?: Record<string, unknown>): ErrorReport {
|
|
114
|
+
return {
|
|
115
|
+
error,
|
|
116
|
+
code: error instanceof XavvaError ? error.code : "UNKNOWN_ERROR",
|
|
117
|
+
exitCode: getExitCode(error),
|
|
118
|
+
isOperational: isOperationalError(error),
|
|
119
|
+
context,
|
|
120
|
+
timestamp: new Date(),
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Adiciona erro ao histórico (com limite)
|
|
126
|
+
*/
|
|
127
|
+
private addToHistory(report: ErrorReport): void {
|
|
128
|
+
this.errorHistory.push(report);
|
|
129
|
+
if (this.errorHistory.length > this.maxHistorySize) {
|
|
130
|
+
this.errorHistory.shift();
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Trata erros específicos do Xavva
|
|
136
|
+
*/
|
|
137
|
+
private handleXavvaError(error: XavvaError): void {
|
|
138
|
+
this.logXavvaError(error, true);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Loga erro Xavva com formatação adequada
|
|
143
|
+
*/
|
|
144
|
+
private logXavvaError(error: XavvaError, isFatal: boolean): void {
|
|
145
|
+
const logMethod = isFatal ? Logger.error : Logger.warn;
|
|
146
|
+
|
|
147
|
+
// Cabeçalho do erro
|
|
148
|
+
logMethod.call(Logger, error.message);
|
|
149
|
+
|
|
150
|
+
// Detalhes adicionais se houver
|
|
151
|
+
if (error instanceof NetworkError) {
|
|
152
|
+
Logger.info("Dica", "Verifique sua conexão de internet e tente novamente");
|
|
153
|
+
} else if (error instanceof FileSystemError) {
|
|
154
|
+
Logger.info("Dica", "Verifique as permissões do arquivo/diretório");
|
|
155
|
+
} else if (error instanceof BuildError) {
|
|
156
|
+
Logger.info("Dica", "Use --verbose para ver detalhes completos do build");
|
|
157
|
+
} else if (error instanceof TomcatError) {
|
|
158
|
+
Logger.info("Dica", "Verifique se o Tomcat está configurado corretamente");
|
|
159
|
+
} else if (error instanceof ConfigError) {
|
|
160
|
+
Logger.info("Dica", "Verifique seu arquivo xavva.json");
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Código do erro em debug
|
|
164
|
+
Logger.debug(`Código do erro: ${error.code} (exit ${error.exitCode})`);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Trata erros inesperados (bugs)
|
|
169
|
+
*/
|
|
170
|
+
private handleUnexpectedError(error: Error): void {
|
|
171
|
+
Logger.error("Erro inesperado:");
|
|
172
|
+
Logger.error(error.message);
|
|
173
|
+
Logger.newline();
|
|
174
|
+
Logger.info("Isso parece ser um bug", "Por favor, reporte em github.com/leorsousa05/Xavva/issues");
|
|
175
|
+
|
|
176
|
+
// Sempre mostra stack trace para erros inesperados
|
|
177
|
+
if (error.stack) {
|
|
178
|
+
Logger.newline();
|
|
179
|
+
Logger.dim("Stack trace:");
|
|
180
|
+
Logger.dim(error.stack.split("\n").slice(1, 5).join("\n"));
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Obtém histórico de erros
|
|
186
|
+
*/
|
|
187
|
+
getErrorHistory(): ErrorReport[] {
|
|
188
|
+
return [...this.errorHistory];
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Limpa histórico de erros
|
|
193
|
+
*/
|
|
194
|
+
clearHistory(): void {
|
|
195
|
+
this.errorHistory = [];
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Verifica se houve erros recentes de um tipo específico
|
|
200
|
+
*/
|
|
201
|
+
hasRecentError(code: string, withinMs: number = 60000): boolean {
|
|
202
|
+
const now = Date.now();
|
|
203
|
+
return this.errorHistory.some(
|
|
204
|
+
report =>
|
|
205
|
+
report.code === code &&
|
|
206
|
+
(now - report.timestamp.getTime()) < withinMs
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Wrapper para executar função com tratamento de erro automático
|
|
212
|
+
*/
|
|
213
|
+
async wrap<T>(
|
|
214
|
+
fn: () => Promise<T>,
|
|
215
|
+
context?: Record<string, unknown>
|
|
216
|
+
): Promise<T | undefined> {
|
|
217
|
+
try {
|
|
218
|
+
return await fn();
|
|
219
|
+
} catch (error) {
|
|
220
|
+
await this.handle(error, context);
|
|
221
|
+
return undefined;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Wrapper para executar função sem shutdown em caso de erro
|
|
227
|
+
*/
|
|
228
|
+
wrapGraceful<T>(
|
|
229
|
+
fn: () => T,
|
|
230
|
+
fallback: T,
|
|
231
|
+
context?: Record<string, unknown>
|
|
232
|
+
): T {
|
|
233
|
+
try {
|
|
234
|
+
return fn();
|
|
235
|
+
} catch (error) {
|
|
236
|
+
this.handleGraceful(error, context);
|
|
237
|
+
return fallback;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Helper para uso rápido
|
|
243
|
+
export function handleError(error: unknown, context?: Record<string, unknown>): Promise<void> {
|
|
244
|
+
return ErrorHandler.getInstance().handle(error, context);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
export function handleGraceful(error: unknown, context?: Record<string, unknown>): ErrorReport {
|
|
248
|
+
return ErrorHandler.getInstance().handleGraceful(error, context);
|
|
249
|
+
}
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hierarquia de erros específicos do Xavva
|
|
3
|
+
* Permite tratamento granular de diferentes tipos de falhas
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export class XavvaError extends Error {
|
|
7
|
+
public readonly code: string;
|
|
8
|
+
public readonly exitCode: number;
|
|
9
|
+
public readonly isOperational: boolean;
|
|
10
|
+
|
|
11
|
+
constructor(
|
|
12
|
+
message: string,
|
|
13
|
+
code: string = "XAVVA_ERROR",
|
|
14
|
+
exitCode: number = 1,
|
|
15
|
+
isOperational: boolean = true
|
|
16
|
+
) {
|
|
17
|
+
super(message);
|
|
18
|
+
this.name = this.constructor.name;
|
|
19
|
+
this.code = code;
|
|
20
|
+
this.exitCode = exitCode;
|
|
21
|
+
this.isOperational = isOperational;
|
|
22
|
+
|
|
23
|
+
// Mantém o stack trace correto
|
|
24
|
+
Error.captureStackTrace(this, this.constructor);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// ===== Erros de Build =====
|
|
29
|
+
export class BuildError extends XavvaError {
|
|
30
|
+
constructor(message: string, details?: string) {
|
|
31
|
+
super(
|
|
32
|
+
details ? `${message}: ${details}` : message,
|
|
33
|
+
"BUILD_ERROR",
|
|
34
|
+
3,
|
|
35
|
+
true
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export class MavenError extends BuildError {
|
|
41
|
+
constructor(message: string, exitCode?: number) {
|
|
42
|
+
super(
|
|
43
|
+
`Maven build failed${exitCode ? ` (exit ${exitCode})` : ""}: ${message}`,
|
|
44
|
+
);
|
|
45
|
+
this.code = "MAVEN_ERROR";
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export class GradleError extends BuildError {
|
|
50
|
+
constructor(message: string, exitCode?: number) {
|
|
51
|
+
super(
|
|
52
|
+
`Gradle build failed${exitCode ? ` (exit ${exitCode})` : ""}: ${message}`,
|
|
53
|
+
);
|
|
54
|
+
this.code = "GRADLE_ERROR";
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// ===== Erros de Deploy =====
|
|
59
|
+
export class DeployError extends XavvaError {
|
|
60
|
+
constructor(message: string, details?: string) {
|
|
61
|
+
super(
|
|
62
|
+
details ? `${message}: ${details}` : message,
|
|
63
|
+
"DEPLOY_ERROR",
|
|
64
|
+
4,
|
|
65
|
+
true
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export class ArtifactNotFoundError extends DeployError {
|
|
71
|
+
constructor(buildDir: string) {
|
|
72
|
+
super(
|
|
73
|
+
`Nenhum artefato (.war ou pasta exploded) encontrado em ${buildDir}`,
|
|
74
|
+
"Certifique-se de que o build foi executado com sucesso"
|
|
75
|
+
);
|
|
76
|
+
this.code = "ARTIFACT_NOT_FOUND";
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// ===== Erros de Tomcat =====
|
|
81
|
+
export class TomcatError extends XavvaError {
|
|
82
|
+
constructor(message: string, details?: string) {
|
|
83
|
+
super(
|
|
84
|
+
details ? `${message}: ${details}` : message,
|
|
85
|
+
"TOMCAT_ERROR",
|
|
86
|
+
5,
|
|
87
|
+
true
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export class TomcatNotFoundError extends TomcatError {
|
|
93
|
+
constructor(path: string) {
|
|
94
|
+
super(
|
|
95
|
+
`Tomcat não encontrado em ${path}`,
|
|
96
|
+
"Defina TOMCAT_HOME, CATALINA_HOME ou use --path"
|
|
97
|
+
);
|
|
98
|
+
this.code = "TOMCAT_NOT_FOUND";
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export class PortInUseError extends TomcatError {
|
|
103
|
+
constructor(port: number) {
|
|
104
|
+
super(
|
|
105
|
+
`Porta ${port} já está em uso`,
|
|
106
|
+
"Pare o processo que está usando a porta ou especifique outra com --port"
|
|
107
|
+
);
|
|
108
|
+
this.code = "PORT_IN_USE";
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export class EmbeddedTomcatError extends TomcatError {
|
|
113
|
+
constructor(message: string) {
|
|
114
|
+
super(
|
|
115
|
+
`Falha no Tomcat embutido: ${message}`,
|
|
116
|
+
"Tente instalar manualmente ou use outra versão com --tomcat-version"
|
|
117
|
+
);
|
|
118
|
+
this.code = "EMBEDDED_TOMCAT_ERROR";
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// ===== Erros de Configuração =====
|
|
123
|
+
export class ConfigError extends XavvaError {
|
|
124
|
+
constructor(message: string, details?: string) {
|
|
125
|
+
super(
|
|
126
|
+
details ? `${message}: ${details}` : message,
|
|
127
|
+
"CONFIG_ERROR",
|
|
128
|
+
2,
|
|
129
|
+
true
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export class InvalidConfigError extends ConfigError {
|
|
135
|
+
constructor(field: string, value: string, expected?: string) {
|
|
136
|
+
super(
|
|
137
|
+
`Configuração inválida: ${field} = '${value}'`,
|
|
138
|
+
expected || "Verifique sua configuração"
|
|
139
|
+
);
|
|
140
|
+
this.code = "INVALID_CONFIG";
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export class MissingConfigError extends ConfigError {
|
|
145
|
+
constructor(field: string) {
|
|
146
|
+
super(
|
|
147
|
+
`Configuração obrigatória ausente: ${field}`,
|
|
148
|
+
`Defina ${field} no xavva.json ou via linha de comando`
|
|
149
|
+
);
|
|
150
|
+
this.code = "MISSING_CONFIG";
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// ===== Erros de Projeto =====
|
|
155
|
+
export class ProjectError extends XavvaError {
|
|
156
|
+
constructor(message: string, details?: string) {
|
|
157
|
+
super(
|
|
158
|
+
details ? `${message}: ${details}` : message,
|
|
159
|
+
"PROJECT_ERROR",
|
|
160
|
+
6,
|
|
161
|
+
true
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export class BuildToolNotFoundError extends ProjectError {
|
|
167
|
+
constructor() {
|
|
168
|
+
super(
|
|
169
|
+
"Não foi possível detectar a ferramenta de build",
|
|
170
|
+
"Certifique-se de estar no diretório raiz do projeto (pom.xml ou build.gradle)"
|
|
171
|
+
);
|
|
172
|
+
this.code = "BUILD_TOOL_NOT_FOUND";
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export class JavaNotFoundError extends ProjectError {
|
|
177
|
+
constructor() {
|
|
178
|
+
super(
|
|
179
|
+
"Java não encontrado",
|
|
180
|
+
"Defina JAVA_HOME ou certifique-se de que 'java' está no PATH"
|
|
181
|
+
);
|
|
182
|
+
this.code = "JAVA_NOT_FOUND";
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// ===== Erros de Audit/Security =====
|
|
187
|
+
export class AuditError extends XavvaError {
|
|
188
|
+
constructor(message: string) {
|
|
189
|
+
super(
|
|
190
|
+
`Erro na auditoria: ${message}`,
|
|
191
|
+
"AUDIT_ERROR",
|
|
192
|
+
7,
|
|
193
|
+
true
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export class NetworkError extends XavvaError {
|
|
199
|
+
public readonly url: string;
|
|
200
|
+
public readonly originalError?: Error;
|
|
201
|
+
|
|
202
|
+
constructor(url: string, originalError?: Error) {
|
|
203
|
+
super(
|
|
204
|
+
`Falha na conexão com ${url}${originalError ? `: ${originalError.message}` : ""}`,
|
|
205
|
+
"NETWORK_ERROR",
|
|
206
|
+
8,
|
|
207
|
+
true
|
|
208
|
+
);
|
|
209
|
+
this.url = url;
|
|
210
|
+
this.originalError = originalError;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// ===== Erros de File System =====
|
|
215
|
+
export class FileSystemError extends XavvaError {
|
|
216
|
+
constructor(message: string, path?: string) {
|
|
217
|
+
super(
|
|
218
|
+
path ? `${message}: ${path}` : message,
|
|
219
|
+
"FILESYSTEM_ERROR",
|
|
220
|
+
9,
|
|
221
|
+
true
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export class FileNotFoundError extends FileSystemError {
|
|
227
|
+
constructor(path: string) {
|
|
228
|
+
super("Arquivo não encontrado", path);
|
|
229
|
+
this.code = "FILE_NOT_FOUND";
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export class PermissionError extends FileSystemError {
|
|
234
|
+
constructor(path: string) {
|
|
235
|
+
super("Permissão negada", path);
|
|
236
|
+
this.code = "PERMISSION_DENIED";
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// ===== Erros de Comando =====
|
|
241
|
+
export class CommandError extends XavvaError {
|
|
242
|
+
constructor(command: string, message: string) {
|
|
243
|
+
super(
|
|
244
|
+
`Erro no comando '${command}': ${message}`,
|
|
245
|
+
"COMMAND_ERROR",
|
|
246
|
+
10,
|
|
247
|
+
true
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
export class UnknownCommandError extends CommandError {
|
|
253
|
+
constructor(command: string) {
|
|
254
|
+
super(command, "Comando desconhecido");
|
|
255
|
+
this.code = "UNKNOWN_COMMAND";
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Helper para identificar se é erro operacional (vs programação)
|
|
260
|
+
export function isOperationalError(error: Error): boolean {
|
|
261
|
+
if (error instanceof XavvaError) {
|
|
262
|
+
return error.isOperational;
|
|
263
|
+
}
|
|
264
|
+
return false;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Helper para obter exit code de qualquer erro
|
|
268
|
+
export function getExitCode(error: Error): number {
|
|
269
|
+
if (error instanceof XavvaError) {
|
|
270
|
+
return error.exitCode;
|
|
271
|
+
}
|
|
272
|
+
return 1; // Erro genérico
|
|
273
|
+
}
|