@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,235 @@
1
+ /**
2
+ * Mensagens de erro contextuais com sugestões e auto-fix
3
+ */
4
+
5
+ import { Logger } from "../logging";
6
+
7
+ export interface ErrorContext {
8
+ message: string;
9
+ suggestion: string;
10
+ docsUrl?: string;
11
+ autoFix?: () => Promise<boolean>;
12
+ command?: string;
13
+ }
14
+
15
+ export const ErrorMessages: Record<string, ErrorContext> = {
16
+ // Build errors
17
+ MAVEN_NOT_FOUND: {
18
+ message: "Maven não encontrado no PATH",
19
+ suggestion: "Instale o Maven ou adicione ao PATH\n" +
20
+ " • Windows: choco install maven\n" +
21
+ " • macOS: brew install maven\n" +
22
+ " • Linux: sudo apt install maven",
23
+ docsUrl: "https://maven.apache.org/install.html",
24
+ command: "xavva doctor --fix",
25
+ },
26
+
27
+ GRADLE_NOT_FOUND: {
28
+ message: "Gradle não encontrado no PATH",
29
+ suggestion: "Instale o Gradle ou adicione ao PATH\n" +
30
+ " • Windows: choco install gradle\n" +
31
+ " • macOS: brew install gradle\n" +
32
+ " • Linux: sdk install gradle",
33
+ docsUrl: "https://gradle.org/install/",
34
+ command: "xavva doctor --fix",
35
+ },
36
+
37
+ BUILD_FAILED: {
38
+ message: "Build falhou",
39
+ suggestion: "Use --verbose para ver detalhes completos\n" +
40
+ "Verifique se todas as dependências estão disponíveis",
41
+ command: "xavva build --verbose",
42
+ },
43
+
44
+ // Tomcat errors
45
+ TOMCAT_NOT_FOUND: {
46
+ message: "Tomcat não encontrado",
47
+ suggestion: "Defina TOMCAT_HOME ou use Tomcat embutido\n" +
48
+ "Execute 'xavva dev --yes' para instalação automática",
49
+ command: "xavva dev --yes",
50
+ },
51
+
52
+ TOMCAT_PORT_IN_USE: {
53
+ message: "Porta {port} já está em uso",
54
+ suggestion: "Escolha outra porta ou pare o processo atual",
55
+ command: "xavva dev --port 8081",
56
+ },
57
+
58
+ // Java errors
59
+ JAVA_NOT_FOUND: {
60
+ message: "Java não encontrado no PATH",
61
+ suggestion: "Instale JDK 11+ ou defina JAVA_HOME\n" +
62
+ "Execute 'xavva doctor --fix' para configuração automática",
63
+ command: "xavva doctor --fix",
64
+ },
65
+
66
+ JAVA_VERSION_TOO_OLD: {
67
+ message: "Versão do Java muito antiga ({version})",
68
+ suggestion: "JDK 11+ é necessário\n" +
69
+ "Execute 'xavva doctor --fix' para instalar JDK moderno",
70
+ command: "xavva doctor --fix",
71
+ },
72
+
73
+ // Config errors
74
+ CONFIG_INVALID: {
75
+ message: "Configuração inválida em xavva.json",
76
+ suggestion: "Verifique sintaxe JSON e campos obrigatórios\n" +
77
+ "Execute 'xavva config' para ver configuração atual",
78
+ command: "xavva config",
79
+ },
80
+
81
+ // Network errors
82
+ DOWNLOAD_FAILED: {
83
+ message: "Falha no download",
84
+ suggestion: "Verifique conexão de internet\n" +
85
+ "Tente novamente em alguns instantes",
86
+ },
87
+
88
+ TIMEOUT: {
89
+ message: "Tempo de espera esgotado",
90
+ suggestion: "Operação demorou muito tempo\n" +
91
+ "Verifique conexão ou tente aumentar o timeout",
92
+ },
93
+
94
+ // File system errors
95
+ PERMISSION_DENIED: {
96
+ message: "Permissão negada",
97
+ suggestion: "Execute com permissões adequadas\n" +
98
+ "Windows: Execute como Administrador\n" +
99
+ "Linux/macOS: Use sudo se necessário",
100
+ },
101
+
102
+ DISK_FULL: {
103
+ message: "Disco cheio",
104
+ suggestion: "Libere espaço em disco\n" +
105
+ "Execute 'xavva clean' para limpar arquivos temporários",
106
+ command: "xavva clean",
107
+ },
108
+
109
+ // Port errors
110
+ PORT_UNAVAILABLE: {
111
+ message: "Porta não disponível",
112
+ suggestion: "Porta pode estar em uso ou bloqueada pelo firewall\n" +
113
+ "Use outra porta: xavva dev --port 8081",
114
+ command: "xavva dev --port 8081",
115
+ },
116
+
117
+ // Watch errors
118
+ WATCH_TOO_MANY_FILES: {
119
+ message: "Muitos arquivos para monitorar",
120
+ suggestion: "Exclua node_modules do watch\n" +
121
+ "Adicione ao .gitignore ou use --exclude",
122
+ },
123
+ };
124
+
125
+ /**
126
+ * Obtém mensagem de erro contextual
127
+ */
128
+ export function getErrorMessage(code: string, params: Record<string, string> = {}): ErrorContext {
129
+ const template = ErrorMessages[code] || {
130
+ message: `Erro desconhecido: ${code}`,
131
+ suggestion: "Consulte a documentação ou reporte o problema",
132
+ };
133
+
134
+ // Substitui parâmetros
135
+ let message = template.message;
136
+ for (const [key, value] of Object.entries(params)) {
137
+ message = message.replace(`{${key}}`, value);
138
+ }
139
+
140
+ return {
141
+ ...template,
142
+ message,
143
+ };
144
+ }
145
+
146
+ /**
147
+ * Mostra erro com contexto
148
+ */
149
+ export function showContextualError(code: string, params: Record<string, string> = {}): void {
150
+ const logger = Logger.getInstance();
151
+ const error = getErrorMessage(code, params);
152
+
153
+ logger.error(error.message);
154
+
155
+ if (error.suggestion) {
156
+ logger.newline();
157
+ logger.info("💡 Dica:");
158
+ for (const line of error.suggestion.split('\n')) {
159
+ logger.info(` ${line}`);
160
+ }
161
+ }
162
+
163
+ if (error.command) {
164
+ logger.newline();
165
+ logger.info(`🔧 Tente: ${error.command}`);
166
+ }
167
+
168
+ if (error.docsUrl) {
169
+ logger.newline();
170
+ logger.url("📖 Documentação", error.docsUrl);
171
+ }
172
+ }
173
+
174
+ /**
175
+ * Tenta executar auto-fix para um erro
176
+ */
177
+ export async function tryAutoFix(code: string): Promise<boolean> {
178
+ const error = ErrorMessages[code];
179
+
180
+ if (!error?.autoFix) {
181
+ return false;
182
+ }
183
+
184
+ const logger = Logger.getInstance();
185
+ logger.info(`🔧 Tentando correção automática...`);
186
+
187
+ try {
188
+ return await error.autoFix();
189
+ } catch (e) {
190
+ logger.error(`Auto-fix falhou: ${(e as Error).message}`);
191
+ return false;
192
+ }
193
+ }
194
+
195
+ /**
196
+ * Detecta código de erro baseado na mensagem
197
+ */
198
+ export function detectErrorCode(message: string): string | null {
199
+ const patterns: Record<string, RegExp[]> = {
200
+ MAVEN_NOT_FOUND: [/mvn[\s\w]*not found/i, /maven.*not.*found/i, /cannot find.*mvn/i],
201
+ GRADLE_NOT_FOUND: [/gradle[\s\w]*not found/i, /cannot find.*gradle/i],
202
+ JAVA_NOT_FOUND: [/java[\s\w]*not found/i, /cannot find.*java/i, /no java/i],
203
+ BUILD_FAILED: [/build failed/i, /compilation failed/i, /failed to compile/i],
204
+ TOMCAT_PORT_IN_USE: [/port.*in use/i, /address already in use/i, /bind.*failed/i],
205
+ PERMISSION_DENIED: [/permission denied/i, /access denied/i, /eacces/i],
206
+ DISK_FULL: [/disk full/i, /no space left/i, /enospc/i],
207
+ TIMEOUT: [/timeout/i, /timed out/i, /etimedout/i],
208
+ };
209
+
210
+ for (const [code, regexes] of Object.entries(patterns)) {
211
+ for (const regex of regexes) {
212
+ if (regex.test(message)) {
213
+ return code;
214
+ }
215
+ }
216
+ }
217
+
218
+ return null;
219
+ }
220
+
221
+ /**
222
+ * Mostra erro genérico com detecção automática
223
+ */
224
+ export function showSmartError(error: Error | string): void {
225
+ const message = error instanceof Error ? error.message : error;
226
+ const code = detectErrorCode(message);
227
+
228
+ if (code) {
229
+ showContextualError(code);
230
+ } else {
231
+ const logger = Logger.getInstance();
232
+ logger.error(message);
233
+ logger.info("Use --verbose para mais detalhes ou consulte a documentação");
234
+ }
235
+ }
package/src/index.ts CHANGED
@@ -7,7 +7,7 @@ import { ErrorHandler } from "./errors/ErrorHandler";
7
7
  import { ProcessManager } from "./utils/processManager";
8
8
  import { LoggerLevel } from "./utils/LoggerLevel";
9
9
  import pkg from "../package.json";
10
- import { Logger } from "./utils/ui";
10
+ import { Logger, C } from "./utils/ui";
11
11
  import type { CLIArguments } from "./types/args";
12
12
 
13
13
  async function main() {
@@ -32,7 +32,7 @@ async function main() {
32
32
  "debug", "logs", "docs", "audit", "profiles",
33
33
  "deps", "tomcat", "encoding", "init", "config",
34
34
  "history", "redo", "health", "completion", "changelog",
35
- "test", "db", "http", "docker", "help"
35
+ "test", "db", "http", "docker", "help", "clean", "ide"
36
36
  ];
37
37
  const commandName = positionals.find(p => commandNames.includes(p)) || "deploy";
38
38
 
@@ -49,9 +49,15 @@ async function main() {
49
49
 
50
50
  // Handler de help
51
51
  if (values.help) {
52
- const { HelpCommand } = await import("./commands/HelpCommand");
53
- new HelpCommand().execute(config, values as CLIArguments);
54
- await processManager.shutdown(0);
52
+ // Se for help de comando específico, deixa o comando tratar
53
+ if (commandName !== "help" && commandName !== "deploy") {
54
+ // O comando específico vai tratar o --help
55
+ } else {
56
+ // Help geral
57
+ const { HelpCommand } = await import("./commands/HelpCommand");
58
+ new HelpCommand().execute(config, values as CLIArguments);
59
+ await processManager.shutdown(0);
60
+ }
55
61
  }
56
62
 
57
63
  // Inicializa Container de DI
@@ -71,7 +77,7 @@ async function main() {
71
77
  if (values.tui) {
72
78
  const deployCmd = commands.deploy;
73
79
  services.dashboardService.onAction("r", () => {
74
- services.dashboardService.log(Logger.C.warning + "Restart manual solicitado via TUI...");
80
+ services.dashboardService.log(C.warning + "Restart manual solicitado via TUI...");
75
81
  deployCmd.execute(config, { watch: true, incremental: false });
76
82
  });
77
83
  }
@@ -116,6 +122,8 @@ async function main() {
116
122
  registry.register("db", commands.db);
117
123
  registry.register("http", commands.http);
118
124
  registry.register("docker", commands.docker);
125
+ registry.register("clean", commands.clean);
126
+ registry.register("ide", commands.ide);
119
127
 
120
128
  // Configura flags específicas
121
129
  if (commandName === "debug") values.debug = true;
@@ -158,6 +166,12 @@ async function main() {
158
166
  }
159
167
  }
160
168
  }
169
+
170
+ // Só encerra o processo se não estiver em modo watch ou TUI
171
+ // (esses modos precisam continuar rodando)
172
+ if (!values.watch && !values.tui) {
173
+ await ProcessManager.getInstance().shutdown(0);
174
+ }
161
175
  }
162
176
 
163
177
  // Entry point com tratamento global de erros
@@ -0,0 +1,235 @@
1
+ /**
2
+ * FileLogger - Persistência de logs em arquivo
3
+ *
4
+ * Salva logs em formato JSON Lines (.jsonl) para fácil integração
5
+ * com ferramentas de análise como ELK, Datadog, etc.
6
+ *
7
+ * Características:
8
+ * - Rotação automática por data
9
+ * - Limite de tamanho por arquivo
10
+ * - Limite de arquivos retidos
11
+ * - Formato estruturado (JSON)
12
+ */
13
+
14
+ import { existsSync, mkdirSync, appendFileSync, readdirSync, statSync, unlinkSync } from 'fs';
15
+ import { join } from 'path';
16
+ import type { LogEntry } from './types';
17
+ import { FILE_LOG } from './constants';
18
+
19
+ export interface FileLoggerOptions {
20
+ logDir: string;
21
+ maxFiles: number;
22
+ maxSize: number;
23
+ enabled: boolean;
24
+ }
25
+
26
+ export class FileLogger {
27
+ private options: FileLoggerOptions;
28
+ private currentFile: string | null = null;
29
+ private currentSize = 0;
30
+ private initialized = false;
31
+
32
+ constructor(options: Partial<FileLoggerOptions> = {}) {
33
+ this.options = {
34
+ logDir: '.xavva/logs',
35
+ maxFiles: FILE_LOG.maxFiles,
36
+ maxSize: FILE_LOG.maxSize,
37
+ enabled: true,
38
+ ...options,
39
+ };
40
+ }
41
+
42
+ /**
43
+ * Inicializa o diretório de logs
44
+ */
45
+ private initialize(): void {
46
+ if (this.initialized || !this.options.enabled) return;
47
+
48
+ try {
49
+ if (!existsSync(this.options.logDir)) {
50
+ mkdirSync(this.options.logDir, { recursive: true });
51
+ }
52
+ this.initialized = true;
53
+ } catch (error) {
54
+ console.error('Falha ao inicializar diretório de logs:', error);
55
+ this.options.enabled = false;
56
+ }
57
+ }
58
+
59
+ /**
60
+ * Obtém o nome do arquivo de log atual
61
+ */
62
+ private getCurrentFileName(): string {
63
+ const date = new Date();
64
+ const year = date.getFullYear();
65
+ const month = String(date.getMonth() + 1).padStart(2, '0');
66
+ const day = String(date.getDate()).padStart(2, '0');
67
+ return join(this.options.logDir, `xavva-${year}-${month}-${day}.jsonl`);
68
+ }
69
+
70
+ /**
71
+ * Verifica se precisa rotacionar para novo arquivo
72
+ */
73
+ private checkRotation(): void {
74
+ const newFile = this.getCurrentFileName();
75
+
76
+ if (this.currentFile !== newFile) {
77
+ // Mudou de dia, atualiza arquivo
78
+ this.currentFile = newFile;
79
+ this.currentSize = existsSync(newFile) ? statSync(newFile).size : 0;
80
+ this.cleanupOldFiles();
81
+ } else if (this.currentFile && this.currentSize > this.options.maxSize) {
82
+ // Arquivo muito grande, cria novo com sufixo
83
+ const timestamp = Date.now();
84
+ this.currentFile = this.currentFile.replace('.jsonl', `-${timestamp}.jsonl`);
85
+ this.currentSize = 0;
86
+ }
87
+ }
88
+
89
+ /**
90
+ * Remove arquivos de log antigos
91
+ */
92
+ private cleanupOldFiles(): void {
93
+ try {
94
+ if (!existsSync(this.options.logDir)) return;
95
+
96
+ const files = readdirSync(this.options.logDir)
97
+ .filter(f => f.startsWith('xavva-') && f.endsWith('.jsonl'))
98
+ .map(f => ({
99
+ name: f,
100
+ path: join(this.options.logDir, f),
101
+ time: statSync(join(this.options.logDir, f)).mtime.getTime(),
102
+ }))
103
+ .sort((a, b) => b.time - a.time); // Mais recente primeiro
104
+
105
+ // Remove arquivos excedentes
106
+ const filesToRemove = files.slice(this.options.maxFiles);
107
+ for (const file of filesToRemove) {
108
+ try {
109
+ unlinkSync(file.path);
110
+ } catch {
111
+ // Ignora erros de deleção
112
+ }
113
+ }
114
+ } catch {
115
+ // Ignora erros de cleanup
116
+ }
117
+ }
118
+
119
+ /**
120
+ * Escreve uma entrada de log no arquivo
121
+ */
122
+ write(entry: LogEntry): void {
123
+ if (!this.options.enabled) return;
124
+
125
+ this.initialize();
126
+ this.checkRotation();
127
+
128
+ if (!this.currentFile) return;
129
+
130
+ try {
131
+ // Formata como JSON Lines
132
+ const logLine = JSON.stringify({
133
+ timestamp: entry.timestamp.toISOString(),
134
+ level: entry.level,
135
+ message: entry.message.replace(/\x1b\[\d+m/g, ''), // Remove ANSI
136
+ traceId: entry.context?.traceId,
137
+ metadata: entry.metadata,
138
+ }) + '\n';
139
+
140
+ appendFileSync(this.currentFile, logLine);
141
+ this.currentSize += Buffer.byteLength(logLine);
142
+ } catch (error) {
143
+ // Falha silenciosa - não deve quebrar a aplicação por causa de log em arquivo
144
+ if (process.env.XAVVA_DEBUG) {
145
+ console.error('Falha ao escrever log em arquivo:', error);
146
+ }
147
+ }
148
+ }
149
+
150
+ /**
151
+ * Habilita/desabilita logging em arquivo
152
+ */
153
+ setEnabled(enabled: boolean): void {
154
+ this.options.enabled = enabled;
155
+ }
156
+
157
+ /**
158
+ * Verifica se está habilitado
159
+ */
160
+ isEnabled(): boolean {
161
+ return this.options.enabled;
162
+ }
163
+
164
+ /**
165
+ * Obtém caminho do diretório de logs
166
+ */
167
+ getLogDir(): string {
168
+ return this.options.logDir;
169
+ }
170
+
171
+ /**
172
+ * Lista arquivos de log existentes
173
+ */
174
+ listLogFiles(): { name: string; path: string; size: number; modified: Date }[] {
175
+ try {
176
+ if (!existsSync(this.options.logDir)) return [];
177
+
178
+ return readdirSync(this.options.logDir)
179
+ .filter(f => f.startsWith('xavva-') && f.endsWith('.jsonl'))
180
+ .map(f => {
181
+ const path = join(this.options.logDir, f);
182
+ const stats = statSync(path);
183
+ return {
184
+ name: f,
185
+ path,
186
+ size: stats.size,
187
+ modified: stats.mtime,
188
+ };
189
+ })
190
+ .sort((a, b) => b.modified.getTime() - a.modified.getTime());
191
+ } catch {
192
+ return [];
193
+ }
194
+ }
195
+
196
+ /**
197
+ * Limpa todos os arquivos de log
198
+ */
199
+ clearAll(): void {
200
+ try {
201
+ const files = this.listLogFiles();
202
+ for (const file of files) {
203
+ unlinkSync(file.path);
204
+ }
205
+ this.currentFile = null;
206
+ this.currentSize = 0;
207
+ } catch {
208
+ // Ignora erros
209
+ }
210
+ }
211
+ }
212
+
213
+ // Instância global
214
+ let globalFileLogger: FileLogger | null = null;
215
+
216
+ /**
217
+ * Obtém instância global do FileLogger
218
+ */
219
+ export function getFileLogger(options?: Partial<FileLoggerOptions>): FileLogger {
220
+ if (!globalFileLogger) {
221
+ globalFileLogger = new FileLogger(options);
222
+ }
223
+ return globalFileLogger;
224
+ }
225
+
226
+ /**
227
+ * Configura o FileLogger global
228
+ */
229
+ export function configureFileLogger(options: Partial<FileLoggerOptions>): void {
230
+ if (globalFileLogger) {
231
+ globalFileLogger = new FileLogger({ ...globalFileLogger, ...options });
232
+ } else {
233
+ globalFileLogger = new FileLogger(options);
234
+ }
235
+ }