@archznn/xavva 2.7.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.
@@ -0,0 +1,302 @@
1
+ import { exec } from "child_process";
2
+ import { promisify } from "util";
3
+ import { platform, totalmem, freemem, arch } from "os";
4
+ import { existsSync } from "fs";
5
+ import type { Command } from "./Command";
6
+ import type { AppConfig, CLIArguments } from "../types/config";
7
+ import { Logger } from "../utils/ui";
8
+
9
+ const execAsync = promisify(exec);
10
+
11
+ interface HealthCheck {
12
+ name: string;
13
+ status: "ok" | "warning" | "error";
14
+ message: string;
15
+ details?: string;
16
+ }
17
+
18
+ export class HealthCommand implements Command {
19
+ async execute(config: AppConfig, _args?: CLIArguments): Promise<void> {
20
+ Logger.banner("health");
21
+ Logger.section("Verificando saúde do ambiente");
22
+
23
+ const checks: HealthCheck[] = [];
24
+
25
+ // Java
26
+ checks.push(await this.checkJava());
27
+
28
+ // Maven/Gradle
29
+ checks.push(await this.checkBuildTool(config.project.buildTool));
30
+
31
+ // Tomcat
32
+ checks.push(await this.checkTomcat(config));
33
+
34
+ // Portas
35
+ checks.push(await this.checkPorts(config.tomcat.port));
36
+
37
+ // Memória
38
+ checks.push(this.checkMemory());
39
+
40
+ // Disco
41
+ checks.push(await this.checkDisk());
42
+
43
+ // Git
44
+ checks.push(this.checkGit());
45
+
46
+ // Exibir resultados
47
+ Logger.newline();
48
+ let errors = 0;
49
+ let warnings = 0;
50
+
51
+ for (const check of checks) {
52
+ const icon = check.status === "ok"
53
+ ? `${Logger.C.success}✓${Logger.C.reset}`
54
+ : check.status === "warning"
55
+ ? `${Logger.C.warning}⚠${Logger.C.reset}`
56
+ : `${Logger.C.error}✗${Logger.C.reset}`;
57
+
58
+ Logger.log(`${Logger.C.gray}│${Logger.C.reset} ${icon} ${Logger.C.bold}${check.name}${Logger.C.reset}`);
59
+ Logger.log(`${Logger.C.gray}│${Logger.C.reset} ${check.message}`);
60
+
61
+ if (check.details) {
62
+ Logger.log(`${Logger.C.gray}│${Logger.C.reset} ${Logger.C.dim}${check.details}${Logger.C.reset}`);
63
+ }
64
+
65
+ if (check.status === "error") errors++;
66
+ if (check.status === "warning") warnings++;
67
+ }
68
+
69
+ Logger.endSection();
70
+
71
+ // Summary
72
+ if (errors === 0 && warnings === 0) {
73
+ Logger.ready("Ambiente saudável! ✓");
74
+ } else if (errors === 0) {
75
+ Logger.warn(`${warnings} aviso(s) encontrado(s)`);
76
+ } else {
77
+ Logger.error(`${errors} erro(s) encontrado(s)`);
78
+ }
79
+ }
80
+
81
+ private async checkJava(): Promise<HealthCheck> {
82
+ try {
83
+ const { stdout, stderr } = await execAsync("java -version");
84
+ const output = stderr || stdout;
85
+ const versionMatch = output.match(/version "?(\d+\.?\d*)/);
86
+ const version = versionMatch ? versionMatch[1] : "unknown";
87
+ const isDCEVM = output.toLowerCase().includes("dcevm") || output.toLowerCase().includes("jbr");
88
+
89
+ const majorVersion = parseInt(version.split(".")[0]);
90
+ const status = majorVersion >= 11 ? "ok" : "warning";
91
+
92
+ return {
93
+ name: "Java",
94
+ status,
95
+ message: `v${version}${isDCEVM ? " + DCEVM" : ""}`,
96
+ details: isDCEVM ? "Hot-reload disponível" : "Considere instalar DCEVM para hot-reload"
97
+ };
98
+ } catch {
99
+ return {
100
+ name: "Java",
101
+ status: "error",
102
+ message: "Java não encontrado",
103
+ details: "Instale o JDK 11+ e configure JAVA_HOME"
104
+ };
105
+ }
106
+ }
107
+
108
+ private async checkBuildTool(tool: string): Promise<HealthCheck> {
109
+ try {
110
+ if (tool === "maven") {
111
+ const { stdout } = await execAsync("mvn -version");
112
+ const version = stdout.match(/Apache Maven (\d+\.\d+\.\d+)/)?.[1] || "unknown";
113
+ return {
114
+ name: "Maven",
115
+ status: "ok",
116
+ message: `v${version}`
117
+ };
118
+ } else {
119
+ const { stdout } = await execAsync("gradle --version");
120
+ const version = stdout.match(/Gradle (\d+\.\d+\.\d+)/)?.[1] || "unknown";
121
+ return {
122
+ name: "Gradle",
123
+ status: "ok",
124
+ message: `v${version}`
125
+ };
126
+ }
127
+ } catch {
128
+ return {
129
+ name: tool === "maven" ? "Maven" : "Gradle",
130
+ status: "error",
131
+ message: `${tool === "maven" ? "mvn" : "gradle"} não encontrado`,
132
+ details: `Instale ${tool === "maven" ? "Maven" : "Gradle"} e adicione ao PATH`
133
+ };
134
+ }
135
+ }
136
+
137
+ private async checkTomcat(config: AppConfig): Promise<HealthCheck> {
138
+ if (config.tomcat.embedded) {
139
+ return {
140
+ name: "Tomcat",
141
+ status: "ok",
142
+ message: `Embutido v${config.tomcat.version || "10.1.52"}`,
143
+ details: "Auto-download habilitado"
144
+ };
145
+ }
146
+
147
+ if (existsSync(config.tomcat.path)) {
148
+ const versionFile = `${config.tomcat.path}/bin/version.sh`;
149
+ const versionBat = `${config.tomcat.path}/bin/version.bat`;
150
+
151
+ try {
152
+ const cmd = existsSync(versionBat) ? versionBat : versionFile;
153
+ const { stdout } = await execAsync(cmd);
154
+ const version = stdout.match(/Server version: Apache Tomcat\/(\d+\.\d+\.\d+)/)?.[1] || "unknown";
155
+ return {
156
+ name: "Tomcat",
157
+ status: "ok",
158
+ message: `v${version}`,
159
+ details: config.tomcat.path
160
+ };
161
+ } catch {
162
+ return {
163
+ name: "Tomcat",
164
+ status: "warning",
165
+ message: "Caminho existe mas não foi possível verificar versão",
166
+ details: config.tomcat.path
167
+ };
168
+ }
169
+ }
170
+
171
+ return {
172
+ name: "Tomcat",
173
+ status: "error",
174
+ message: "Caminho não encontrado",
175
+ details: `Configure CATALINA_HOME ou use Tomcat embutido`
176
+ };
177
+ }
178
+
179
+ private async checkPorts(port: number): Promise<HealthCheck> {
180
+ try {
181
+ let cmd: string;
182
+ if (platform() === "win32") {
183
+ cmd = `netstat -an | findstr :${port}`;
184
+ } else if (platform() === "darwin") {
185
+ cmd = `lsof -i :${port}`;
186
+ } else {
187
+ cmd = `ss -tuln | grep :${port}`;
188
+ }
189
+
190
+ const { stdout } = await execAsync(cmd);
191
+ const isInUse = stdout.trim().length > 0;
192
+
193
+ if (isInUse) {
194
+ return {
195
+ name: "Portas",
196
+ status: "warning",
197
+ message: `Porta ${port} em uso`,
198
+ details: "Outro processo pode estar usando a porta"
199
+ };
200
+ }
201
+
202
+ return {
203
+ name: "Portas",
204
+ status: "ok",
205
+ message: `Porta ${port} disponível`
206
+ };
207
+ } catch {
208
+ // Comando falhou, assume que porta está livre
209
+ return {
210
+ name: "Portas",
211
+ status: "ok",
212
+ message: `Porta ${port} parece disponível`
213
+ };
214
+ }
215
+ }
216
+
217
+ private checkMemory(): HealthCheck {
218
+ const total = totalmem();
219
+ const free = freemem();
220
+ const used = total - free;
221
+ const percentUsed = Math.round((used / total) * 100);
222
+ const freeGB = (free / 1024 / 1024 / 1024).toFixed(1);
223
+ const totalGB = (total / 1024 / 1024 / 1024).toFixed(1);
224
+
225
+ const status = percentUsed > 90 ? "warning" : "ok";
226
+
227
+ return {
228
+ name: "Memória",
229
+ status,
230
+ message: `${freeGB}GB livre de ${totalGB}GB`,
231
+ details: `${percentUsed}% em uso`
232
+ };
233
+ }
234
+
235
+ private async checkDisk(): Promise<HealthCheck> {
236
+ try {
237
+ let cmd: string;
238
+ if (platform() === "win32") {
239
+ cmd = "wmic logicaldisk get size,freespace,caption";
240
+ } else {
241
+ cmd = "df -h .";
242
+ }
243
+
244
+ const { stdout } = await execAsync(cmd);
245
+
246
+ if (platform() === "win32") {
247
+ const lines = stdout.trim().split("\n").slice(1);
248
+ const mainDisk = lines.find(l => l.includes(":")) || "";
249
+ const parts = mainDisk.trim().split(/\s+/);
250
+ if (parts.length >= 3) {
251
+ const free = parseInt(parts[0]) / 1024 / 1024 / 1024;
252
+ const total = parseInt(parts[1]) / 1024 / 1024 / 1024;
253
+ const percentFree = Math.round((free / total) * 100);
254
+
255
+ return {
256
+ name: "Disco",
257
+ status: percentFree < 10 ? "warning" : "ok",
258
+ message: `${free.toFixed(1)}GB livre`,
259
+ details: `${percentFree}% disponível`
260
+ };
261
+ }
262
+ } else {
263
+ const match = stdout.match(/(\d+)%/);
264
+ if (match) {
265
+ const used = parseInt(match[1]);
266
+ return {
267
+ name: "Disco",
268
+ status: used > 90 ? "warning" : "ok",
269
+ message: `${100 - used}% disponível`,
270
+ details: stdout.split("\n")[1]?.split(/\s+/).pop() || ""
271
+ };
272
+ }
273
+ }
274
+
275
+ throw new Error("Could not parse disk info");
276
+ } catch {
277
+ return {
278
+ name: "Disco",
279
+ status: "warning",
280
+ message: "Não foi possível verificar",
281
+ details: "Verifique manualmente"
282
+ };
283
+ }
284
+ }
285
+
286
+ private checkGit(): HealthCheck {
287
+ if (existsSync(".git")) {
288
+ return {
289
+ name: "Git",
290
+ status: "ok",
291
+ message: "Repositório Git detectado"
292
+ };
293
+ }
294
+
295
+ return {
296
+ name: "Git",
297
+ status: "warning",
298
+ message: "Sem repositório Git",
299
+ details: "Execute 'git init' para versionamento"
300
+ };
301
+ }
302
+ }
@@ -31,6 +31,13 @@ export class HelpCommand implements Command {
31
31
  ${this.c("green", "tomcat")} Manage embedded Tomcat (install, list, installed, use, status)
32
32
  ${this.c("green", "docs")} Generate endpoint documentation
33
33
  ${this.c("green", "encoding")} Convert file encoding (detect, convert, fix, list)
34
+
35
+ ${this.c("cyan", "init")} Initialize project configuration (wizard)
36
+ ${this.c("cyan", "config")} View/edit configuration (--interactive)
37
+ ${this.c("cyan", "history")} Show command history
38
+ ${this.c("cyan", "redo")} Repeat last command
39
+ ${this.c("cyan", "health")} Check environment health
40
+ ${this.c("cyan", "completion")} Generate shell completions (bash/zsh/fish)
34
41
 
35
42
  ${this.c("yellow", "GENERAL OPTIONS")}
36
43
  ${this.c("cyan", "-p, --path")} <path> Tomcat installation path
@@ -112,6 +119,26 @@ export class HelpCommand implements Command {
112
119
  xavva encoding fix src/main/java/MinhaClasse.java # Fix mojibake
113
120
  xavva encoding list # List all file encodings
114
121
 
122
+ ${this.c("dim", "# Initialize new project")}
123
+ xavva init # Interactive wizard
124
+
125
+ ${this.c("dim", "# Manage configuration")}
126
+ xavva config # View current config
127
+ xavva config --interactive # Edit config interactively
128
+
129
+ ${this.c("dim", "# Command history")}
130
+ xavva history # Show recent commands
131
+ xavva history --clear # Clear history
132
+ xavva redo # Repeat last command
133
+
134
+ ${this.c("dim", "# Health check")}
135
+ xavva health # Check environment health
136
+
137
+ ${this.c("dim", "# Shell completions")}
138
+ xavva completion bash # Generate bash completions
139
+ xavva completion zsh # Generate zsh completions
140
+ eval "$(xavva completion bash)" # Enable in current shell
141
+
115
142
  ${this.c("yellow", "CONFIGURATION")}
116
143
  Settings are loaded from ${this.c("cyan", "xavva.json")} in the project root:
117
144
 
@@ -0,0 +1,49 @@
1
+ import type { Command } from "./Command";
2
+ import type { AppConfig, CLIArguments } from "../types/config";
3
+ import { HistoryService } from "../services/HistoryService";
4
+ import { Logger } from "../utils/ui";
5
+
6
+ export class HistoryCommand implements Command {
7
+ private historyService = new HistoryService();
8
+
9
+ async execute(_config: AppConfig, args?: CLIArguments): Promise<void> {
10
+ const clear = args?.["clear"] || false;
11
+ const limit = parseInt(String(args?.["limit"] || "10"));
12
+
13
+ if (clear) {
14
+ await this.historyService.clear();
15
+ Logger.success("Histórico limpo!");
16
+ return;
17
+ }
18
+
19
+ const entries = await this.historyService.getRecent(limit);
20
+ const stats = await this.historyService.getStats();
21
+
22
+ Logger.banner("history");
23
+ Logger.section(`Últimos ${entries.length} comandos`);
24
+
25
+ if (entries.length === 0) {
26
+ Logger.dim("Nenhum comando no histórico");
27
+ Logger.endSection();
28
+ return;
29
+ }
30
+
31
+ for (let i = 0; i < entries.length; i++) {
32
+ const entry = entries[i];
33
+ const date = new Date(entry.timestamp);
34
+ const time = date.toLocaleTimeString("pt-BR", { hour: "2-digit", minute: "2-digit" });
35
+ const icon = entry.success
36
+ ? `${Logger.C.success}✓${Logger.C.reset}`
37
+ : `${Logger.C.error}✗${Logger.C.reset}`;
38
+
39
+ const args = entry.args.length > 0 ? entry.args.join(" ") : "";
40
+ const duration = entry.duration ? `${Logger.C.gray}(${entry.duration.toFixed(1)}s)${Logger.C.reset}` : "";
41
+
42
+ Logger.log(`${Logger.C.gray}│${Logger.C.reset} ${Logger.C.dim}${time}${Logger.C.reset} ${icon} ${Logger.C.white}xavva ${entry.command}${Logger.C.reset} ${Logger.C.gray}${args}${Logger.C.reset} ${duration}`);
43
+ }
44
+
45
+ Logger.endSection();
46
+ Logger.info(`Total: ${stats.total} | Sucesso: ${stats.successful} | Falha: ${stats.failed}`);
47
+ Logger.dim("Use 'xavva redo' para repetir o último comando");
48
+ }
49
+ }
@@ -0,0 +1,148 @@
1
+ import { input, select, confirm, number } from "@inquirer/prompts";
2
+ import { writeFile, access } from "fs/promises";
3
+ import { join } from "path";
4
+ import { constants } from "fs";
5
+ import type { Command } from "./Command";
6
+ import type { AppConfig, CLIArguments } from "../types/config";
7
+ import { Logger } from "../utils/ui";
8
+
9
+ export class InitCommand implements Command {
10
+ async execute(_config: AppConfig, _args?: CLIArguments): Promise<void> {
11
+ Logger.banner("init");
12
+ Logger.section("Wizard de Configuração");
13
+ Logger.info("Vamos configurar seu projeto Xavva");
14
+ Logger.newline();
15
+
16
+ // Detectar build tool
17
+ const buildTool = await this.detectBuildTool();
18
+
19
+ // Nome da aplicação
20
+ const appName = await input({
21
+ message: "Nome da aplicação:",
22
+ default: process.cwd().split(/[/\\]/).pop() || "my-app",
23
+ validate: (value) => value.length > 0 || "Nome é obrigatório"
24
+ });
25
+
26
+ // Profile
27
+ const profile = await select({
28
+ message: "Profile padrão:",
29
+ choices: [
30
+ { name: "desenvolvimento", value: "dev" },
31
+ { name: "teste", value: "test" },
32
+ { name: "produção", value: "prod" },
33
+ { name: "customizado", value: "custom" }
34
+ ],
35
+ default: "dev"
36
+ });
37
+
38
+ const customProfile = profile === "custom" ? await input({
39
+ message: "Nome do profile:",
40
+ default: "local"
41
+ }) : profile;
42
+
43
+ // Porta do Tomcat
44
+ const port = await number({
45
+ message: "Porta do Tomcat:",
46
+ default: 8080,
47
+ validate: (value) => (value && value > 0 && value < 65536) || "Porta inválida"
48
+ }) || 8080;
49
+
50
+ // Configurações opcionais
51
+ Logger.newline();
52
+ Logger.dim("Configurações avançadas:");
53
+
54
+ const useEmbedded = await confirm({
55
+ message: "Usar Tomcat embutido (auto-download)?",
56
+ default: true
57
+ });
58
+
59
+ const enableCache = await confirm({
60
+ message: "Habilitar cache de build?",
61
+ default: true
62
+ });
63
+
64
+ const enableTui = await confirm({
65
+ message: "Habilitar dashboard TUI?",
66
+ default: true
67
+ });
68
+
69
+ const encoding = await select({
70
+ message: "Encoding:",
71
+ choices: [
72
+ { name: "UTF-8", value: "UTF-8" },
73
+ { name: "ISO-8859-1", value: "ISO-8859-1" },
74
+ { name: "Windows-1252", value: "Windows-1252" }
75
+ ],
76
+ default: "UTF-8"
77
+ });
78
+
79
+ // Montar configuração
80
+ const config: Record<string, unknown> = {
81
+ appName,
82
+ buildTool,
83
+ profile: customProfile,
84
+ port,
85
+ cache: enableCache,
86
+ tui: enableTui,
87
+ encoding
88
+ };
89
+
90
+ if (useEmbedded) {
91
+ config.embedded = true;
92
+ config.tomcatVersion = "10.1.52";
93
+ } else {
94
+ const tomcatPath = await input({
95
+ message: "Caminho do Tomcat (CATALINA_HOME):",
96
+ validate: async (value) => {
97
+ if (!value) return "Caminho é obrigatório";
98
+ try {
99
+ await access(value, constants.R_OK);
100
+ return true;
101
+ } catch {
102
+ return "Caminho não acessível";
103
+ }
104
+ }
105
+ });
106
+ config.tomcatPath = tomcatPath;
107
+ }
108
+
109
+ // Salvar arquivo
110
+ Logger.newline();
111
+ Logger.step("Salvando configuração...");
112
+
113
+ const configPath = join(process.cwd(), "xavva.json");
114
+ await writeFile(configPath, JSON.stringify(config, null, 2));
115
+
116
+ Logger.success(`Configuração salva em ${configPath}`);
117
+ Logger.newline();
118
+ Logger.ready("Projeto configurado!");
119
+ Logger.info("Próximos passos:");
120
+ Logger.log(` ${Logger.C.gray}│${Logger.C.reset} ${Logger.C.primary}xavva build${Logger.C.reset} ${Logger.C.gray}- Compilar projeto${Logger.C.reset}`);
121
+ Logger.log(` ${Logger.C.gray}│${Logger.C.reset} ${Logger.C.primary}xavva deploy${Logger.C.reset} ${Logger.C.gray}- Build + deploy${Logger.C.reset}`);
122
+ Logger.log(` ${Logger.C.gray}│${Logger.C.reset} ${Logger.C.primary}xavva doctor${Logger.C.reset} ${Logger.C.gray}- Verificar ambiente${Logger.C.reset}`);
123
+ Logger.done();
124
+ }
125
+
126
+ private async detectBuildTool(): Promise<"maven" | "gradle"> {
127
+ try {
128
+ await access(join(process.cwd(), "pom.xml"), constants.R_OK);
129
+ Logger.info("Detectado: Projeto Maven");
130
+ return "maven";
131
+ } catch {
132
+ try {
133
+ await access(join(process.cwd(), "build.gradle"), constants.R_OK);
134
+ Logger.info("Detectado: Projeto Gradle");
135
+ return "gradle";
136
+ } catch {
137
+ const choice = await select({
138
+ message: "Build tool:",
139
+ choices: [
140
+ { name: "Maven", value: "maven" },
141
+ { name: "Gradle", value: "gradle" }
142
+ ]
143
+ });
144
+ return choice;
145
+ }
146
+ }
147
+ }
148
+ }
@@ -0,0 +1,36 @@
1
+ import type { Command } from "./Command";
2
+ import type { AppConfig, CLIArguments } from "../types/config";
3
+ import { HistoryService } from "../services/HistoryService";
4
+ import { Logger } from "../utils/ui";
5
+ import { ProcessManager } from "../utils/processManager";
6
+
7
+ export class RedoCommand implements Command {
8
+ private historyService = new HistoryService();
9
+
10
+ async execute(_config: AppConfig, _args?: CLIArguments): Promise<void> {
11
+ const lastEntry = await this.historyService.getLast();
12
+
13
+ if (!lastEntry) {
14
+ Logger.error("Nenhum comando no histórico");
15
+ return;
16
+ }
17
+
18
+ const args = lastEntry.args.length > 0 ? lastEntry.args.join(" ") : "";
19
+ Logger.banner("redo");
20
+ Logger.info(`Repetindo: ${Logger.C.white}xavva ${lastEntry.command}${Logger.C.reset} ${Logger.C.gray}${args}${Logger.C.reset}`);
21
+ Logger.newline();
22
+
23
+ // Re-executar o comando
24
+ const proc = Bun.spawn([
25
+ "bun", "run", "src/index.ts",
26
+ lastEntry.command,
27
+ ...lastEntry.args
28
+ ], {
29
+ stdio: "inherit",
30
+ cwd: process.cwd()
31
+ });
32
+
33
+ await proc.exited;
34
+ ProcessManager.getInstance().shutdown(proc.exitCode || 0);
35
+ }
36
+ }
@@ -24,6 +24,14 @@ import { DepsCommand } from "../commands/DepsCommand";
24
24
  import { TomcatCommand } from "../commands/TomcatCommand";
25
25
  import { EncodingCommand } from "../commands/EncodingCommand";
26
26
  import { DocsCommand } from "../commands/DocsCommand";
27
+ import { InitCommand } from "../commands/InitCommand";
28
+ import { ConfigCommand } from "../commands/ConfigCommand";
29
+ import { HistoryCommand } from "../commands/HistoryCommand";
30
+ import { RedoCommand } from "../commands/RedoCommand";
31
+ import { HealthCommand } from "../commands/HealthCommand";
32
+ import { CompletionCommand } from "../commands/CompletionCommand";
33
+ import { HistoryService } from "../services/HistoryService";
34
+ import { NotificationService } from "../services/NotificationService";
27
35
  import type { Command } from "../commands/Command";
28
36
  import { Logger } from "../utils/ui";
29
37
 
@@ -35,6 +43,7 @@ export interface Services {
35
43
  auditService: AuditService;
36
44
  dashboardService: DashboardService;
37
45
  logAnalyzer: LogAnalyzer;
46
+ historyService: HistoryService;
38
47
  }
39
48
 
40
49
  export interface Commands {
@@ -53,6 +62,12 @@ export interface Commands {
53
62
  tomcat: TomcatCommand;
54
63
  encoding: EncodingCommand;
55
64
  docs: DocsCommand;
65
+ init: InitCommand;
66
+ config: ConfigCommand;
67
+ history: HistoryCommand;
68
+ redo: RedoCommand;
69
+ health: HealthCommand;
70
+ completion: CompletionCommand;
56
71
  }
57
72
 
58
73
  export class DIContainer {
@@ -101,6 +116,7 @@ export class DIContainer {
101
116
  tomcatService.setProjectService(projectService);
102
117
 
103
118
  const auditService = new AuditService(this.config.tomcat);
119
+ const historyService = new HistoryService();
104
120
 
105
121
  this.services = {
106
122
  projectService,
@@ -110,6 +126,7 @@ export class DIContainer {
110
126
  auditService,
111
127
  dashboardService,
112
128
  logAnalyzer,
129
+ historyService,
113
130
  };
114
131
  }
115
132
 
@@ -140,6 +157,12 @@ export class DIContainer {
140
157
  tomcat: new TomcatCommand(),
141
158
  encoding: new EncodingCommand(),
142
159
  docs: new DocsCommand(),
160
+ init: new InitCommand(),
161
+ config: new ConfigCommand(),
162
+ history: new HistoryCommand(),
163
+ redo: new RedoCommand(),
164
+ health: new HealthCommand(),
165
+ completion: new CompletionCommand(),
143
166
  };
144
167
  }
145
168