@archznn/xavva 2.0.2 → 2.1.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 +165 -39
- 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 +4 -2
- package/src/commands/DepsCommand.ts +123 -0
- package/src/commands/DoctorCommand.ts +5 -4
- package/src/commands/HelpCommand.ts +94 -39
- package/src/commands/ProfilesCommand.ts +32 -0
- package/src/commands/RunCommand.ts +13 -12
- package/src/commands/StartCommand.ts +5 -3
- package/src/index.ts +17 -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 +31 -12
- package/src/services/DependencyAnalyzerService.ts +538 -0
- package/src/services/ProjectService.ts +39 -1
- 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 +7 -4
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { Command } from "./Command";
|
|
2
|
+
import type { AppConfig, CLIArguments } from "../types/config";
|
|
3
|
+
import { ProjectService } from "../services/ProjectService";
|
|
4
|
+
import { Logger } from "../utils/ui";
|
|
5
|
+
|
|
6
|
+
export class ProfilesCommand implements Command {
|
|
7
|
+
constructor(private projectService: ProjectService) {}
|
|
8
|
+
|
|
9
|
+
async execute(config: AppConfig, args?: CLIArguments): Promise<void> {
|
|
10
|
+
Logger.section("Project Profiles");
|
|
11
|
+
|
|
12
|
+
Logger.info("Build Tool", config.project.buildTool.toUpperCase());
|
|
13
|
+
|
|
14
|
+
const profiles = this.projectService.getAvailableProfiles();
|
|
15
|
+
|
|
16
|
+
if (profiles.length === 0) {
|
|
17
|
+
Logger.warn("Nenhum perfil específico encontrado no arquivo de configuração.");
|
|
18
|
+
Logger.log(` ${Logger.C.dim}Dica: Perfis Maven são definidos em <profiles> no pom.xml.${Logger.C.reset}`);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
Logger.log(`
|
|
23
|
+
${Logger.C.cyan}Perfis detectados:${Logger.C.reset}`);
|
|
24
|
+
profiles.forEach(p => {
|
|
25
|
+
const active = config.project.profile === p ? ` ${Logger.C.green}(Ativo)${Logger.C.reset}` : "";
|
|
26
|
+
Logger.log(` ${Logger.C.bold}➜${Logger.C.reset} ${p}${active}`);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
Logger.newline();
|
|
30
|
+
Logger.log(` ${Logger.C.dim}Para usar um perfil: xavva build -P nome-do-perfil${Logger.C.reset}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -2,6 +2,9 @@ import type { Command } from "./Command";
|
|
|
2
2
|
import type { AppConfig, CLIArguments } from "../types/config";
|
|
3
3
|
import { Logger } from "../utils/ui";
|
|
4
4
|
import path from "path";
|
|
5
|
+
import fs from "fs";
|
|
6
|
+
import { glob } from "glob";
|
|
7
|
+
import readline from "readline";
|
|
5
8
|
|
|
6
9
|
export class RunCommand implements Command {
|
|
7
10
|
async execute(config: AppConfig, args?: CLIArguments): Promise<void> {
|
|
@@ -39,6 +42,10 @@ export class RunCommand implements Command {
|
|
|
39
42
|
"-classpath", finalCp,
|
|
40
43
|
];
|
|
41
44
|
|
|
45
|
+
if (config.project.encoding) {
|
|
46
|
+
javaArgs.push(`-Dfile.encoding=${config.project.encoding}`);
|
|
47
|
+
}
|
|
48
|
+
|
|
42
49
|
if (isDebug) {
|
|
43
50
|
javaArgs.push("-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005");
|
|
44
51
|
}
|
|
@@ -70,8 +77,6 @@ export class RunCommand implements Command {
|
|
|
70
77
|
}
|
|
71
78
|
|
|
72
79
|
private async discoverClass(simpleName: string): Promise<string | null> {
|
|
73
|
-
const fs = require("fs");
|
|
74
|
-
const glob = require("glob");
|
|
75
80
|
const basePaths = [
|
|
76
81
|
path.join(process.cwd(), "src/main/java"),
|
|
77
82
|
path.join(process.cwd(), "src/test/java"),
|
|
@@ -134,14 +139,14 @@ export class RunCommand implements Command {
|
|
|
134
139
|
Logger.log(` [${i + 1}] ${c}`);
|
|
135
140
|
});
|
|
136
141
|
|
|
137
|
-
const
|
|
142
|
+
const rl = readline.createInterface({
|
|
138
143
|
input: process.stdin,
|
|
139
144
|
output: process.stdout
|
|
140
145
|
});
|
|
141
146
|
|
|
142
147
|
return new Promise((resolve) => {
|
|
143
|
-
|
|
144
|
-
|
|
148
|
+
rl.question(` Escolha a classe (1-${uniqueClasses.length}) ou [C]ancelar: `, (answer: string) => {
|
|
149
|
+
rl.close();
|
|
145
150
|
const idx = parseInt(answer) - 1;
|
|
146
151
|
if (!isNaN(idx) && uniqueClasses[idx]) {
|
|
147
152
|
resolve(uniqueClasses[idx]);
|
|
@@ -154,7 +159,6 @@ export class RunCommand implements Command {
|
|
|
154
159
|
}
|
|
155
160
|
|
|
156
161
|
private async loadFromHistory(): Promise<string | null> {
|
|
157
|
-
const fs = require("fs");
|
|
158
162
|
const xavvaDir = path.join(process.cwd(), ".xavva");
|
|
159
163
|
const historyFile = path.join(xavvaDir, "history.json");
|
|
160
164
|
|
|
@@ -169,14 +173,14 @@ export class RunCommand implements Command {
|
|
|
169
173
|
Logger.log(` [${i + 1}] ${c}${i === 0 ? " (Enter)" : ""}`);
|
|
170
174
|
});
|
|
171
175
|
|
|
172
|
-
const
|
|
176
|
+
const rl = readline.createInterface({
|
|
173
177
|
input: process.stdin,
|
|
174
178
|
output: process.stdout
|
|
175
179
|
});
|
|
176
180
|
|
|
177
181
|
return new Promise((resolve) => {
|
|
178
|
-
|
|
179
|
-
|
|
182
|
+
rl.question(` Escolha a classe (1-${Math.min(history.length, 5)}) ou [C]ancelar: `, (answer: string) => {
|
|
183
|
+
rl.close();
|
|
180
184
|
if (!answer.trim()) {
|
|
181
185
|
resolve(history[0]);
|
|
182
186
|
return;
|
|
@@ -195,7 +199,6 @@ export class RunCommand implements Command {
|
|
|
195
199
|
}
|
|
196
200
|
|
|
197
201
|
private saveToHistory(className: string) {
|
|
198
|
-
const fs = require("fs");
|
|
199
202
|
const xavvaDir = path.join(process.cwd(), ".xavva");
|
|
200
203
|
const historyFile = path.join(xavvaDir, "history.json");
|
|
201
204
|
|
|
@@ -214,7 +217,6 @@ export class RunCommand implements Command {
|
|
|
214
217
|
}
|
|
215
218
|
|
|
216
219
|
private async createPathingJar(dependencyCp: string): Promise<string> {
|
|
217
|
-
const fs = require("fs");
|
|
218
220
|
const xavvaDir = path.join(process.cwd(), ".xavva");
|
|
219
221
|
const jarPath = path.join(xavvaDir, "classpath.jar");
|
|
220
222
|
|
|
@@ -285,7 +287,6 @@ export class RunCommand implements Command {
|
|
|
285
287
|
}
|
|
286
288
|
|
|
287
289
|
private async getClasspath(config: AppConfig): Promise<{ localCp: string, dependencyCp: string }> {
|
|
288
|
-
const fs = require("fs");
|
|
289
290
|
const xavvaDir = path.join(process.cwd(), ".xavva");
|
|
290
291
|
const cpFile = path.join(xavvaDir, "classpath.txt");
|
|
291
292
|
|
|
@@ -2,6 +2,7 @@ import type { Command } from "./Command";
|
|
|
2
2
|
import type { AppConfig } from "../types/config";
|
|
3
3
|
import { TomcatService } from "../services/TomcatService";
|
|
4
4
|
import { Logger } from "../utils/ui";
|
|
5
|
+
import { ProcessManager } from "../utils/processManager";
|
|
5
6
|
|
|
6
7
|
export class StartCommand implements Command {
|
|
7
8
|
constructor(private tomcat: TomcatService) {}
|
|
@@ -20,9 +21,10 @@ export class StartCommand implements Command {
|
|
|
20
21
|
tomcat.start(config, false);
|
|
21
22
|
|
|
22
23
|
await new Promise(() => {});
|
|
23
|
-
} catch (error
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
} catch (error) {
|
|
25
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
26
|
+
Logger.error(message);
|
|
27
|
+
await ProcessManager.getInstance().shutdown(1);
|
|
26
28
|
}
|
|
27
29
|
}
|
|
28
30
|
}
|
package/src/index.ts
CHANGED
|
@@ -10,6 +10,8 @@ import { RunCommand } from "./commands/RunCommand";
|
|
|
10
10
|
import { LogsCommand } from "./commands/LogsCommand";
|
|
11
11
|
import { DocsCommand } from "./commands/DocsCommand";
|
|
12
12
|
import { AuditCommand } from "./commands/AuditCommand";
|
|
13
|
+
import { ProfilesCommand } from "./commands/ProfilesCommand";
|
|
14
|
+
import { DepsCommand } from "./commands/DepsCommand";
|
|
13
15
|
|
|
14
16
|
import { ProjectService } from "./services/ProjectService";
|
|
15
17
|
import { TomcatService } from "./services/TomcatService";
|
|
@@ -22,26 +24,31 @@ import { LogAnalyzer } from "./services/LogAnalyzer";
|
|
|
22
24
|
|
|
23
25
|
import pkg from "../package.json";
|
|
24
26
|
import { Logger } from "./utils/ui";
|
|
27
|
+
import { ProcessManager } from "./utils/processManager";
|
|
25
28
|
import type { AppConfig, CLIArguments } from "./types/config";
|
|
26
29
|
|
|
27
30
|
async function main() {
|
|
31
|
+
const processManager = ProcessManager.getInstance();
|
|
28
32
|
const { config, positionals, values } = await ConfigManager.load();
|
|
29
33
|
|
|
30
34
|
if (values.version) {
|
|
31
35
|
Logger.log(`v${pkg.version}`);
|
|
32
|
-
|
|
36
|
+
await processManager.shutdown(0);
|
|
33
37
|
}
|
|
34
38
|
|
|
35
|
-
const commandNames = ["deploy", "build", "start", "dev", "doctor", "run", "debug", "logs", "docs", "audit"];
|
|
39
|
+
const commandNames = ["deploy", "build", "start", "dev", "doctor", "run", "debug", "logs", "docs", "audit", "profiles", "deps"];
|
|
36
40
|
const commandName = positionals.find(p => commandNames.includes(p)) || "deploy";
|
|
37
41
|
|
|
38
42
|
if (!values.help && !values.tui) {
|
|
39
|
-
Logger.banner(commandName);
|
|
43
|
+
Logger.banner(commandName, config.project.profile, config.project.encoding);
|
|
44
|
+
if (config.project.encoding) {
|
|
45
|
+
Logger.config("Encoding", config.project.encoding);
|
|
46
|
+
}
|
|
40
47
|
}
|
|
41
48
|
|
|
42
49
|
if (values.help) {
|
|
43
50
|
new HelpCommand().execute(config, values);
|
|
44
|
-
|
|
51
|
+
await processManager.shutdown(0);
|
|
45
52
|
}
|
|
46
53
|
|
|
47
54
|
// 1. Instanciar Serviços (Injeção de Dependência)
|
|
@@ -71,6 +78,8 @@ async function main() {
|
|
|
71
78
|
registry.register("logs", logsCmd);
|
|
72
79
|
registry.register("docs", new DocsCommand());
|
|
73
80
|
registry.register("audit", new AuditCommand(auditService));
|
|
81
|
+
registry.register("profiles", new ProfilesCommand(projectService));
|
|
82
|
+
registry.register("deps", new DepsCommand());
|
|
74
83
|
registry.register("deploy", deployCmd);
|
|
75
84
|
registry.register("dev", deployCmd);
|
|
76
85
|
|
|
@@ -95,4 +104,7 @@ async function main() {
|
|
|
95
104
|
}
|
|
96
105
|
}
|
|
97
106
|
|
|
98
|
-
main().catch(
|
|
107
|
+
main().catch(async (error) => {
|
|
108
|
+
console.error(error);
|
|
109
|
+
await ProcessManager.getInstance().shutdown(1);
|
|
110
|
+
});
|
|
@@ -19,6 +19,32 @@ export interface JarAuditResult {
|
|
|
19
19
|
vulnerabilities: Vulnerability[];
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
// Interfaces para resposta da OSV API
|
|
23
|
+
interface OSVEvent {
|
|
24
|
+
fixed?: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
interface OSVRange {
|
|
28
|
+
events: OSVEvent[];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
interface OSVAffected {
|
|
32
|
+
ranges: OSVRange[];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
interface OSVVulnerability {
|
|
36
|
+
id: string;
|
|
37
|
+
summary?: string;
|
|
38
|
+
details?: string;
|
|
39
|
+
affected?: OSVAffected[];
|
|
40
|
+
database_specific?: { severity?: string };
|
|
41
|
+
advisories?: { url: string }[];
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
interface OSVResponse {
|
|
45
|
+
vulns?: OSVVulnerability[];
|
|
46
|
+
}
|
|
47
|
+
|
|
22
48
|
export class AuditService {
|
|
23
49
|
constructor(private tomcatConfig: TomcatConfig) {}
|
|
24
50
|
|
|
@@ -120,22 +146,22 @@ export class AuditService {
|
|
|
120
146
|
})
|
|
121
147
|
});
|
|
122
148
|
|
|
123
|
-
const data = await response.json();
|
|
149
|
+
const data = (await response.json()) as OSVResponse;
|
|
124
150
|
if (!data.vulns) return [];
|
|
125
151
|
|
|
126
|
-
return data.vulns.map((v
|
|
152
|
+
return data.vulns.map((v) => ({
|
|
127
153
|
id: v.id,
|
|
128
154
|
summary: v.summary || v.details?.substring(0, 100) + "...",
|
|
129
155
|
details: v.details,
|
|
130
156
|
severity: this.extractSeverity(v),
|
|
131
|
-
fixedIn: v.affected?.[0]?.ranges?.[0]?.events?.find((e
|
|
157
|
+
fixedIn: v.affected?.[0]?.ranges?.[0]?.events?.find((e) => e.fixed)?.fixed
|
|
132
158
|
}));
|
|
133
159
|
} catch (e) {
|
|
134
160
|
return [];
|
|
135
161
|
}
|
|
136
162
|
}
|
|
137
163
|
|
|
138
|
-
private extractSeverity(vuln:
|
|
164
|
+
private extractSeverity(vuln: OSVVulnerability): string {
|
|
139
165
|
if (vuln.database_specific?.severity) return vuln.database_specific.severity;
|
|
140
166
|
if (vuln.advisories?.[0]?.url?.includes("github.com/advisories")) {
|
|
141
167
|
const d = (vuln.details || "").toLowerCase();
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import fs from "fs";
|
|
2
2
|
import path from "path";
|
|
3
3
|
import crypto from "crypto";
|
|
4
|
+
import type { ProjectService } from "./ProjectService";
|
|
4
5
|
|
|
5
6
|
export interface CacheData {
|
|
6
7
|
lastConfigHash: string;
|
|
@@ -41,7 +42,7 @@ export class BuildCacheService {
|
|
|
41
42
|
return crypto.createHash("md5").update(hash).digest("hex");
|
|
42
43
|
}
|
|
43
44
|
|
|
44
|
-
shouldRebuild(tool: "maven" | "gradle", projectService?:
|
|
45
|
+
shouldRebuild(tool: "maven" | "gradle", projectService?: ProjectService): boolean {
|
|
45
46
|
if (!fs.existsSync(this.cacheFile)) return true;
|
|
46
47
|
|
|
47
48
|
try {
|
|
@@ -38,7 +38,7 @@ export class BuildService {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
const command = [];
|
|
41
|
-
const env:
|
|
41
|
+
const env: Record<string, string | undefined> = { ...process.env };
|
|
42
42
|
|
|
43
43
|
if (this.projectConfig.buildTool === 'maven') {
|
|
44
44
|
command.push(process.platform === "win32" ? "mvn.cmd" : "mvn");
|
|
@@ -57,6 +57,10 @@ export class BuildService {
|
|
|
57
57
|
}
|
|
58
58
|
command.push("-Dmaven.test.skip=true", "-Dmaven.javadoc.skip=true");
|
|
59
59
|
if (this.projectConfig.profile) command.push(`-P${this.projectConfig.profile}`);
|
|
60
|
+
if (this.projectConfig.encoding) {
|
|
61
|
+
command.push(`-Dproject.build.sourceEncoding=${this.projectConfig.encoding}`);
|
|
62
|
+
command.push(`-Dproject.reporting.outputEncoding=${this.projectConfig.encoding}`);
|
|
63
|
+
}
|
|
60
64
|
|
|
61
65
|
env.MAVEN_OPTS = "-Xms512m -Xmx1024m -XX:+UseParallelGC";
|
|
62
66
|
} else {
|
|
@@ -70,6 +74,9 @@ export class BuildService {
|
|
|
70
74
|
}
|
|
71
75
|
command.push("-x", "test", "-x", "javadoc");
|
|
72
76
|
if (this.projectConfig.profile) command.push(`-Pprofile=${this.projectConfig.profile}`);
|
|
77
|
+
if (this.projectConfig.encoding) {
|
|
78
|
+
command.push(`-Dfile.encoding=${this.projectConfig.encoding}`);
|
|
79
|
+
}
|
|
73
80
|
|
|
74
81
|
env.GRADLE_OPTS = "-Xmx1024m -Dorg.gradle.daemon=true";
|
|
75
82
|
}
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import { Logger } from "../utils/ui";
|
|
2
|
+
import { ProcessManager } from "../utils/processManager";
|
|
3
|
+
import {
|
|
4
|
+
MAX_LOG_SCROLLBUFFER,
|
|
5
|
+
DASHBOARD_REFRESH_INTERVAL_MS,
|
|
6
|
+
DASHBOARD_LOG_SLICE_LINES
|
|
7
|
+
} from "../utils/constants";
|
|
2
8
|
import type { AppConfig } from "../types/config";
|
|
3
9
|
import os from "os";
|
|
4
10
|
|
|
@@ -8,7 +14,7 @@ export class DashboardService {
|
|
|
8
14
|
private maxLogLines: number = 0;
|
|
9
15
|
private status: string = "IDLE";
|
|
10
16
|
private statusColor: string = Logger.C.dim;
|
|
11
|
-
private gitContext:
|
|
17
|
+
private gitContext: { branch: string; commit: string } | null = null;
|
|
12
18
|
private actions: Map<string, () => void> = new Map();
|
|
13
19
|
|
|
14
20
|
constructor(private config: AppConfig) {
|
|
@@ -17,6 +23,23 @@ export class DashboardService {
|
|
|
17
23
|
this.gitContext = Logger.getGitContext();
|
|
18
24
|
this.maxLogLines = process.stdout.rows - 6;
|
|
19
25
|
this.setupTui();
|
|
26
|
+
this.registerShutdownHandlers();
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
private registerShutdownHandlers() {
|
|
31
|
+
const processManager = ProcessManager.getInstance();
|
|
32
|
+
processManager.onShutdown(() => {
|
|
33
|
+
this.restoreTerminal();
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
private restoreTerminal() {
|
|
38
|
+
if (this.isTui) {
|
|
39
|
+
process.stdout.write("\x1B[?1049l"); // Restore buffer
|
|
40
|
+
process.stdout.write("\x1B[?25h"); // Show cursor
|
|
41
|
+
process.stdin.setRawMode(false);
|
|
42
|
+
process.stdin.pause();
|
|
20
43
|
}
|
|
21
44
|
}
|
|
22
45
|
|
|
@@ -72,8 +95,8 @@ export class DashboardService {
|
|
|
72
95
|
if (this.isTui) {
|
|
73
96
|
const lines = message.split("\n");
|
|
74
97
|
this.logLines.push(...lines);
|
|
75
|
-
if (this.logLines.length >
|
|
76
|
-
this.logLines = this.logLines.slice(-
|
|
98
|
+
if (this.logLines.length > MAX_LOG_SCROLLBUFFER) {
|
|
99
|
+
this.logLines = this.logLines.slice(-DASHBOARD_LOG_SLICE_LINES);
|
|
77
100
|
}
|
|
78
101
|
this.render();
|
|
79
102
|
} else {
|
|
@@ -92,8 +115,9 @@ export class DashboardService {
|
|
|
92
115
|
const name = (process.cwd().split(/[/\\]/).pop() || "PROJECT").toUpperCase();
|
|
93
116
|
const mem = Math.round((os.totalmem() - os.freemem()) / 1024 / 1024 / 1024 * 10) / 10;
|
|
94
117
|
const totalMem = Math.round(os.totalmem() / 1024 / 1024 / 1024);
|
|
118
|
+
const profile = this.config.project.profile ? ` ${Logger.C.dim}•${Logger.C.reset} ${Logger.C.yellow}♦ ${this.config.project.profile.toUpperCase()}${Logger.C.reset}` : "";
|
|
95
119
|
|
|
96
|
-
output += `${Logger.C.bold}${Logger.C.cyan} X A V V A 2.0 ${Logger.C.reset} ${Logger.C.dim}│${Logger.C.reset} ${Logger.C.white}${Logger.C.bold}${name}${Logger.C.reset}\x1B[K\n`;
|
|
120
|
+
output += `${Logger.C.bold}${Logger.C.cyan} X A V V A 2.0 ${Logger.C.reset} ${Logger.C.dim}│${Logger.C.reset} ${Logger.C.white}${Logger.C.bold}${name}${Logger.C.reset}${profile}\x1B[K\n`;
|
|
97
121
|
output += `${Logger.C.dim} STATUS: ${this.statusColor}${this.status.padEnd(10)}${Logger.C.reset} ${Logger.C.dim}│ MEM: ${Logger.C.yellow}${mem}G/${totalMem}G${Logger.C.reset} ${Logger.C.dim}│ BRANCH: ${Logger.C.magenta}${this.gitContext?.branch || "unknown"}${Logger.C.reset}\x1B[K\n`;
|
|
98
122
|
output += `${Logger.C.dim}──────────────────────────────────────────────────────────────────────────${Logger.C.reset}\x1B[K\n`;
|
|
99
123
|
|
|
@@ -111,13 +135,8 @@ export class DashboardService {
|
|
|
111
135
|
process.stdout.write(output);
|
|
112
136
|
}
|
|
113
137
|
|
|
114
|
-
private exit() {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
process.stdout.write("\x1B[?25h"); // Show cursor
|
|
118
|
-
process.stdin.setRawMode(false);
|
|
119
|
-
process.stdin.pause();
|
|
120
|
-
}
|
|
121
|
-
process.exit(0);
|
|
138
|
+
private async exit() {
|
|
139
|
+
this.restoreTerminal();
|
|
140
|
+
await ProcessManager.getInstance().shutdown(0);
|
|
122
141
|
}
|
|
123
142
|
}
|