aiservermanager 0.1.1
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 +31 -0
- package/backend/dist/di/container.js +80 -0
- package/backend/dist/di/container.js.map +1 -0
- package/backend/dist/di/types.js +18 -0
- package/backend/dist/di/types.js.map +1 -0
- package/backend/dist/files/validatePassword.ps1 +10 -0
- package/backend/dist/files/wmiGpuQuery.ps1 +15 -0
- package/backend/dist/helpers/ExecTools.js +101 -0
- package/backend/dist/helpers/ExecTools.js.map +1 -0
- package/backend/dist/index.js +51 -0
- package/backend/dist/index.js.map +1 -0
- package/backend/dist/middleware/authMiddleware.js +32 -0
- package/backend/dist/middleware/authMiddleware.js.map +1 -0
- package/backend/dist/models/GpuInfo.js +3 -0
- package/backend/dist/models/GpuInfo.js.map +1 -0
- package/backend/dist/models/ServiceConfig.js +46 -0
- package/backend/dist/models/ServiceConfig.js.map +1 -0
- package/backend/dist/models/ServiceStatus.js +3 -0
- package/backend/dist/models/ServiceStatus.js.map +1 -0
- package/backend/dist/routes/authRoutes.js +46 -0
- package/backend/dist/routes/authRoutes.js.map +1 -0
- package/backend/dist/routes/gpuRoutes.js +35 -0
- package/backend/dist/routes/gpuRoutes.js.map +1 -0
- package/backend/dist/routes/serviceRoutes.js +206 -0
- package/backend/dist/routes/serviceRoutes.js.map +1 -0
- package/backend/dist/routes/systemRoutes.js +64 -0
- package/backend/dist/routes/systemRoutes.js.map +1 -0
- package/backend/dist/services/auth/linuxPasswordVerifier.js +74 -0
- package/backend/dist/services/auth/linuxPasswordVerifier.js.map +1 -0
- package/backend/dist/services/auth/passwordVerifier.js +3 -0
- package/backend/dist/services/auth/passwordVerifier.js.map +1 -0
- package/backend/dist/services/auth/windowsPasswordVerifier.js +73 -0
- package/backend/dist/services/auth/windowsPasswordVerifier.js.map +1 -0
- package/backend/dist/services/authService.js +240 -0
- package/backend/dist/services/authService.js.map +1 -0
- package/backend/dist/services/configManager.js +96 -0
- package/backend/dist/services/configManager.js.map +1 -0
- package/backend/dist/services/controllers/systemctlController.js +287 -0
- package/backend/dist/services/controllers/systemctlController.js.map +1 -0
- package/backend/dist/services/controllers/windowsServiceController.js +201 -0
- package/backend/dist/services/controllers/windowsServiceController.js.map +1 -0
- package/backend/dist/services/detectors/amdLinuxDetector.js +127 -0
- package/backend/dist/services/detectors/amdLinuxDetector.js.map +1 -0
- package/backend/dist/services/detectors/gpuDetector.js +3 -0
- package/backend/dist/services/detectors/gpuDetector.js.map +1 -0
- package/backend/dist/services/detectors/nvidiaSmiDetector.js +67 -0
- package/backend/dist/services/detectors/nvidiaSmiDetector.js.map +1 -0
- package/backend/dist/services/detectors/wmiDetector.js +125 -0
- package/backend/dist/services/detectors/wmiDetector.js.map +1 -0
- package/backend/dist/services/enrichers/gpuEnricher.js +3 -0
- package/backend/dist/services/enrichers/gpuEnricher.js.map +1 -0
- package/backend/dist/services/enrichers/lspciEnricher.js +92 -0
- package/backend/dist/services/enrichers/lspciEnricher.js.map +1 -0
- package/backend/dist/services/enrichers/vulkanEnricher.js +57 -0
- package/backend/dist/services/enrichers/vulkanEnricher.js.map +1 -0
- package/backend/dist/services/gpuService.js +108 -0
- package/backend/dist/services/gpuService.js.map +1 -0
- package/backend/dist/services/helpers/gpuDedup.js +46 -0
- package/backend/dist/services/helpers/gpuDedup.js.map +1 -0
- package/backend/dist/services/helpers/gpuEngineNames.js +22 -0
- package/backend/dist/services/helpers/gpuEngineNames.js.map +1 -0
- package/backend/dist/services/llamaAutocompleteService.js +277 -0
- package/backend/dist/services/llamaAutocompleteService.js.map +1 -0
- package/backend/dist/services/managedServicesController.js +72 -0
- package/backend/dist/services/managedServicesController.js.map +1 -0
- package/backend/dist/services/managedServicesManager.js +91 -0
- package/backend/dist/services/managedServicesManager.js.map +1 -0
- package/backend/dist/services/probes/amdLinuxUsageProbe.js +109 -0
- package/backend/dist/services/probes/amdLinuxUsageProbe.js.map +1 -0
- package/backend/dist/services/probes/gpuUsageProbe.js +3 -0
- package/backend/dist/services/probes/gpuUsageProbe.js.map +1 -0
- package/backend/dist/services/probes/nvidiaSmiUsageProbe.js +67 -0
- package/backend/dist/services/probes/nvidiaSmiUsageProbe.js.map +1 -0
- package/backend/dist/services/providers/systemInfoLinuxProvider.js +188 -0
- package/backend/dist/services/providers/systemInfoLinuxProvider.js.map +1 -0
- package/backend/dist/services/providers/systemInfoWindowsProvider.js +101 -0
- package/backend/dist/services/providers/systemInfoWindowsProvider.js.map +1 -0
- package/backend/dist/services/serviceConfigController.js +116 -0
- package/backend/dist/services/serviceConfigController.js.map +1 -0
- package/backend/dist/services/serviceController.js +3 -0
- package/backend/dist/services/serviceController.js.map +1 -0
- package/backend/dist/services/serviceManager.js +157 -0
- package/backend/dist/services/serviceManager.js.map +1 -0
- package/backend/dist/services/systemInfoProvider.js +3 -0
- package/backend/dist/services/systemInfoProvider.js.map +1 -0
- package/backend/dist/services/systemService.js +42 -0
- package/backend/dist/services/systemService.js.map +1 -0
- package/backend/public/browser/chunk-34LU6STA.js +1 -0
- package/backend/public/browser/chunk-JGNPKRLU.js +4 -0
- package/backend/public/browser/favicon.svg +11 -0
- package/backend/public/browser/index.html +15 -0
- package/backend/public/browser/main-MUMQYBNS.js +5579 -0
- package/backend/public/browser/polyfills-5CFQRCPP.js +2 -0
- package/backend/public/browser/styles-QBUDNRKH.css +1 -0
- package/bin/aiservermanager.js +2 -0
- package/package.json +45 -0
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
19
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
20
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
21
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
22
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
23
|
+
};
|
|
24
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
25
|
+
var ownKeys = function(o) {
|
|
26
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
27
|
+
var ar = [];
|
|
28
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
29
|
+
return ar;
|
|
30
|
+
};
|
|
31
|
+
return ownKeys(o);
|
|
32
|
+
};
|
|
33
|
+
return function (mod) {
|
|
34
|
+
if (mod && mod.__esModule) return mod;
|
|
35
|
+
var result = {};
|
|
36
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
37
|
+
__setModuleDefault(result, mod);
|
|
38
|
+
return result;
|
|
39
|
+
};
|
|
40
|
+
})();
|
|
41
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
42
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
43
|
+
};
|
|
44
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
45
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
46
|
+
};
|
|
47
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
48
|
+
exports.AuthService = void 0;
|
|
49
|
+
const crypto = __importStar(require("crypto"));
|
|
50
|
+
const fs = __importStar(require("fs"));
|
|
51
|
+
const os = __importStar(require("os"));
|
|
52
|
+
const path = __importStar(require("path"));
|
|
53
|
+
const inversify_1 = require("inversify");
|
|
54
|
+
const types_1 = require("../di/types");
|
|
55
|
+
const CONFIG_DIR = path.join(os.homedir(), ".config", "aiservermanager");
|
|
56
|
+
const SECRET_FILE = path.join(CONFIG_DIR, "auth-secret");
|
|
57
|
+
/**
|
|
58
|
+
* Authentication service: password verification + JWT token generation.
|
|
59
|
+
*
|
|
60
|
+
* Delegates password verification to an injected PasswordVerifier (platform-specific).
|
|
61
|
+
* JWT secret is persisted to ~/.config/aiservermanager/auth-secret so that
|
|
62
|
+
* tokens remain valid across server restarts.
|
|
63
|
+
*
|
|
64
|
+
* Brute-force protection:
|
|
65
|
+
* - Per-IP rate limit: max 10 login attempts per minute
|
|
66
|
+
* - Account lockout: after 5 consecutive failures → locked for 15 minutes
|
|
67
|
+
*/
|
|
68
|
+
let AuthService = class AuthService {
|
|
69
|
+
verifier;
|
|
70
|
+
jwtSecret;
|
|
71
|
+
username;
|
|
72
|
+
// Brute-force protection state
|
|
73
|
+
failedByIp = new Map(); // IP → sorted timestamps
|
|
74
|
+
maxAttempts = 10;
|
|
75
|
+
windowMs = 60_000; // 1 minute
|
|
76
|
+
consecutiveLimit = 5;
|
|
77
|
+
lockoutMs = 15 * 60 * 1000; // 15 min
|
|
78
|
+
LOCKOUT_FILE = path.join(CONFIG_DIR, "lockout.json");
|
|
79
|
+
_consecutiveFails = 0;
|
|
80
|
+
_lockoutUntil = 0;
|
|
81
|
+
constructor(verifier) {
|
|
82
|
+
this.verifier = verifier;
|
|
83
|
+
this.jwtSecret = this.loadOrCreateSecret();
|
|
84
|
+
this.username = os.userInfo().username;
|
|
85
|
+
this.loadLockoutState();
|
|
86
|
+
// Cleanup stale entries every 5 min
|
|
87
|
+
setInterval(() => this.cleanupStale(), 5 * 60 * 1000);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Check if an IP is rate-limited. Returns null or { retryAfter: seconds }.
|
|
91
|
+
*/
|
|
92
|
+
checkRateLimit(ip) {
|
|
93
|
+
const now = Date.now();
|
|
94
|
+
// Global lockout
|
|
95
|
+
if (now < this._lockoutUntil) {
|
|
96
|
+
return { retryAfter: Math.ceil((this._lockoutUntil - now) / 1000) };
|
|
97
|
+
}
|
|
98
|
+
// Per-IP rate limit
|
|
99
|
+
const timestamps = this.failedByIp.get(ip) ?? [];
|
|
100
|
+
const recent = timestamps.filter((t) => now - t < this.windowMs);
|
|
101
|
+
if (recent.length >= this.maxAttempts) {
|
|
102
|
+
const oldest = Math.min(...recent);
|
|
103
|
+
return { retryAfter: Math.ceil((oldest + this.windowMs - now) / 1000) };
|
|
104
|
+
}
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Verify system password and return a JWT token, or null on failure.
|
|
109
|
+
* Rate limit is checked by the route BEFORE this method is called.
|
|
110
|
+
*/
|
|
111
|
+
async login(ip, password) {
|
|
112
|
+
if (!password)
|
|
113
|
+
return null;
|
|
114
|
+
// Timing-safe: verify lockout BEFORE touching the verifier
|
|
115
|
+
// (route already checks rateLimit, but this is belt-and-suspenders)
|
|
116
|
+
if (Date.now() < this._lockoutUntil) {
|
|
117
|
+
this.recordAttempt(ip);
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
const valid = await this.verifier.verify(password);
|
|
121
|
+
if (valid) {
|
|
122
|
+
// Success — reset lockout state
|
|
123
|
+
this._consecutiveFails = 0;
|
|
124
|
+
this._lockoutUntil = 0;
|
|
125
|
+
this.persistLockoutState();
|
|
126
|
+
return this.generateToken();
|
|
127
|
+
}
|
|
128
|
+
// Failure — record for rate limit + update lockout
|
|
129
|
+
this.recordAttempt(ip);
|
|
130
|
+
this._consecutiveFails++;
|
|
131
|
+
if (this._consecutiveFails >= this.consecutiveLimit) {
|
|
132
|
+
this._lockoutUntil = Date.now() + this.lockoutMs;
|
|
133
|
+
console.warn(`[AuthService] Account locked for 15 min after ${this._consecutiveFails} consecutive failures`);
|
|
134
|
+
}
|
|
135
|
+
this.persistLockoutState();
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
/** Verify a JWT token and return the decoded payload. */
|
|
139
|
+
verifyToken(token) {
|
|
140
|
+
try {
|
|
141
|
+
const decoded = this.signToken(token, true);
|
|
142
|
+
return { username: decoded.username };
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
// ── Brute-force tracking ──
|
|
149
|
+
recordAttempt(ip) {
|
|
150
|
+
const now = Date.now();
|
|
151
|
+
const timestamps = this.failedByIp.get(ip) ?? [];
|
|
152
|
+
timestamps.push(now);
|
|
153
|
+
this.failedByIp.set(ip, timestamps);
|
|
154
|
+
}
|
|
155
|
+
cleanupStale() {
|
|
156
|
+
const now = Date.now();
|
|
157
|
+
for (const [ip, timestamps] of this.failedByIp.entries()) {
|
|
158
|
+
const pruned = timestamps.filter((t) => now - t < this.windowMs);
|
|
159
|
+
if (pruned.length === 0) {
|
|
160
|
+
this.failedByIp.delete(ip);
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
this.failedByIp.set(ip, pruned);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
persistLockoutState() {
|
|
168
|
+
try {
|
|
169
|
+
fs.writeFileSync(this.LOCKOUT_FILE, JSON.stringify({ consecutiveFails: this._consecutiveFails, lockoutUntil: this._lockoutUntil }), "utf-8");
|
|
170
|
+
}
|
|
171
|
+
catch (err) {
|
|
172
|
+
console.error("[AuthService] Failed to persist lockout state:", err);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
loadLockoutState() {
|
|
176
|
+
try {
|
|
177
|
+
const raw = fs.readFileSync(this.LOCKOUT_FILE, "utf-8");
|
|
178
|
+
const data = JSON.parse(raw);
|
|
179
|
+
if (typeof data.consecutiveFails === "number")
|
|
180
|
+
this._consecutiveFails = data.consecutiveFails;
|
|
181
|
+
if (typeof data.lockoutUntil === "number")
|
|
182
|
+
this._lockoutUntil = data.lockoutUntil;
|
|
183
|
+
// If lockout expired while server was down, reset
|
|
184
|
+
if (Date.now() >= this._lockoutUntil) {
|
|
185
|
+
this._consecutiveFails = 0;
|
|
186
|
+
this._lockoutUntil = 0;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
catch {
|
|
190
|
+
// File doesn't exist yet — normal on first run
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
// ── JWT ──
|
|
194
|
+
generateToken() {
|
|
195
|
+
const now = Math.floor(Date.now() / 1000);
|
|
196
|
+
const header = Buffer.from(JSON.stringify({ alg: "HS256", typ: "JWT" })).toString("base64url");
|
|
197
|
+
const payload = Buffer.from(JSON.stringify({ username: this.username, iat: now, exp: now + 7 * 24 * 60 * 60 })).toString("base64url");
|
|
198
|
+
const signature = this.computeHmac(`${header}.${payload}`);
|
|
199
|
+
return `${header}.${payload}.${signature}`;
|
|
200
|
+
}
|
|
201
|
+
signToken(token, _verifyOnly) {
|
|
202
|
+
const parts = token.split(".");
|
|
203
|
+
if (parts.length !== 3)
|
|
204
|
+
throw new Error("Invalid token format");
|
|
205
|
+
const signature = this.computeHmac(`${parts[0]}.${parts[1]}`);
|
|
206
|
+
if (parts[2] !== signature)
|
|
207
|
+
throw new Error("Invalid signature");
|
|
208
|
+
const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString());
|
|
209
|
+
if (payload.exp && Math.floor(Date.now() / 1000) > payload.exp)
|
|
210
|
+
throw new Error("Token expired");
|
|
211
|
+
return payload;
|
|
212
|
+
}
|
|
213
|
+
computeHmac(data) {
|
|
214
|
+
return crypto.createHmac("sha256", this.jwtSecret).update(data).digest("base64url");
|
|
215
|
+
}
|
|
216
|
+
// ── JWT secret persistence ──
|
|
217
|
+
loadOrCreateSecret() {
|
|
218
|
+
if (process.env.AUTH_SECRET)
|
|
219
|
+
return process.env.AUTH_SECRET;
|
|
220
|
+
try {
|
|
221
|
+
const existing = fs.readFileSync(SECRET_FILE, "utf-8").trim();
|
|
222
|
+
if (existing.length > 0)
|
|
223
|
+
return existing;
|
|
224
|
+
}
|
|
225
|
+
catch {
|
|
226
|
+
// File doesn't exist yet
|
|
227
|
+
}
|
|
228
|
+
const secret = crypto.randomBytes(32).toString("hex");
|
|
229
|
+
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
230
|
+
fs.writeFileSync(SECRET_FILE, secret, { mode: 0o600 });
|
|
231
|
+
return secret;
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
exports.AuthService = AuthService;
|
|
235
|
+
exports.AuthService = AuthService = __decorate([
|
|
236
|
+
(0, inversify_1.injectable)(),
|
|
237
|
+
__param(0, (0, inversify_1.inject)(types_1.PASSWORD_VERIFIER)),
|
|
238
|
+
__metadata("design:paramtypes", [Object])
|
|
239
|
+
], AuthService);
|
|
240
|
+
//# sourceMappingURL=authService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authService.js","sourceRoot":"","sources":["../../src/services/authService.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.ConfigManager = void 0;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const ServiceConfig_1 = require("../models/ServiceConfig");
|
|
40
|
+
const CONFIG_DIR = path.join(process.env.HOME ?? "", ".config", "aiservermanager", "services");
|
|
41
|
+
/**
|
|
42
|
+
* Manages service config files in ~/.config/aiservermanager/services/*.conf
|
|
43
|
+
* Each file is named <service-name>.conf and stores command + flags.
|
|
44
|
+
*/
|
|
45
|
+
class ConfigManager {
|
|
46
|
+
/** Ensure the config directory exists. */
|
|
47
|
+
ensureDir() {
|
|
48
|
+
if (!fs.existsSync(CONFIG_DIR)) {
|
|
49
|
+
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/** Get the absolute path for a service name's config file. */
|
|
53
|
+
configPath(name) {
|
|
54
|
+
return path.join(CONFIG_DIR, `${name}.conf`);
|
|
55
|
+
}
|
|
56
|
+
/** List all service configs. */
|
|
57
|
+
list() {
|
|
58
|
+
this.ensureDir();
|
|
59
|
+
const entries = fs.readdirSync(CONFIG_DIR).filter((f) => f.endsWith(".conf"));
|
|
60
|
+
const configs = [];
|
|
61
|
+
for (const entry of entries) {
|
|
62
|
+
const name = entry.replace(/\.conf$/, "");
|
|
63
|
+
const raw = fs.readFileSync(this.configPath(name), "utf-8");
|
|
64
|
+
try {
|
|
65
|
+
configs.push((0, ServiceConfig_1.parseConfigFile)(name, raw));
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
// Skip unparseable configs
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return configs.sort((a, b) => a.name.localeCompare(b.name));
|
|
72
|
+
}
|
|
73
|
+
/** Get a single service config by name. */
|
|
74
|
+
get(name) {
|
|
75
|
+
const p = this.configPath(name);
|
|
76
|
+
if (!fs.existsSync(p))
|
|
77
|
+
return null;
|
|
78
|
+
return (0, ServiceConfig_1.parseConfigFile)(name, fs.readFileSync(p, "utf-8"));
|
|
79
|
+
}
|
|
80
|
+
/** Save (create or update) a service config. */
|
|
81
|
+
save(cfg) {
|
|
82
|
+
this.ensureDir();
|
|
83
|
+
fs.writeFileSync(this.configPath(cfg.name), (0, ServiceConfig_1.serializeConfig)(cfg), "utf-8");
|
|
84
|
+
}
|
|
85
|
+
/** Delete a service config file. Returns true if the file existed. */
|
|
86
|
+
delete(name) {
|
|
87
|
+
const p = this.configPath(name);
|
|
88
|
+
if (fs.existsSync(p)) {
|
|
89
|
+
fs.unlinkSync(p);
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
exports.ConfigManager = ConfigManager;
|
|
96
|
+
//# sourceMappingURL=configManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"configManager.js","sourceRoot":"","sources":["../../src/services/configManager.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,uCAAyB;AACzB,2CAA6B;AAC7B,2DAA0F;AAE1F,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,EAAE,SAAS,EAAE,iBAAiB,EAAE,UAAU,CAAC,CAAC;AAE/F;;;GAGG;AACH,MAAa,aAAa;IACxB,0CAA0C;IAClC,SAAS;QACf,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC/B,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAChD,CAAC;IACH,CAAC;IAED,8DAA8D;IACtD,UAAU,CAAC,IAAY;QAC7B,OAAO,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,IAAI,OAAO,CAAC,CAAC;IAC/C,CAAC;IAED,gCAAgC;IAChC,IAAI;QACF,IAAI,CAAC,SAAS,EAAE,CAAC;QACjB,MAAM,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;QAE9E,MAAM,OAAO,GAAoB,EAAE,CAAC;QACpC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;YAC1C,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC;YAC5D,IAAI,CAAC;gBACH,OAAO,CAAC,IAAI,CAAC,IAAA,+BAAe,EAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC;YAC3C,CAAC;YAAC,MAAM,CAAC;gBACP,2BAA2B;YAC7B,CAAC;QACH,CAAC;QACD,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAC9D,CAAC;IAED,2CAA2C;IAC3C,GAAG,CAAC,IAAY;QACd,MAAM,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QAChC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;QACnC,OAAO,IAAA,+BAAe,EAAC,IAAI,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;IAC5D,CAAC;IAED,gDAAgD;IAChD,IAAI,CAAC,GAAkB;QACrB,IAAI,CAAC,SAAS,EAAE,CAAC;QACjB,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,IAAA,+BAAe,EAAC,GAAG,CAAC,EAAE,OAAO,CAAC,CAAC;IAC7E,CAAC;IAED,sEAAsE;IACtE,MAAM,CAAC,IAAY;QACjB,MAAM,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QAChC,IAAI,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;YACrB,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;YACjB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;CACF;AArDD,sCAqDC"}
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.SystemctlController = void 0;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const ExecTools_1 = require("../../helpers/ExecTools");
|
|
40
|
+
const configManager_1 = require("../configManager");
|
|
41
|
+
const SYSTEM_UNIT_DIR = "/etc/systemd/system";
|
|
42
|
+
/** Manage services via systemctl (Linux with systemd). */
|
|
43
|
+
class SystemctlController {
|
|
44
|
+
configManager = new configManager_1.ConfigManager();
|
|
45
|
+
_hasSudo = null;
|
|
46
|
+
/** Check if a service name has a custom config. */
|
|
47
|
+
hasCustomConfig(name) {
|
|
48
|
+
return this.configManager.get(name) !== null;
|
|
49
|
+
}
|
|
50
|
+
async isAvailable() {
|
|
51
|
+
if (process.platform !== "linux")
|
|
52
|
+
return false;
|
|
53
|
+
const { stdout } = await ExecTools_1.ExecTools.safeExec("systemctl --version");
|
|
54
|
+
return stdout.trim().length > 0;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Check if the process can execute privileged commands (root or passwordless sudo).
|
|
58
|
+
*/
|
|
59
|
+
async checkSudo() {
|
|
60
|
+
if (this._hasSudo !== null)
|
|
61
|
+
return this._hasSudo;
|
|
62
|
+
// Check if running as root (UID 0)
|
|
63
|
+
const { stdout: uidOut } = await ExecTools_1.ExecTools.safeExec("id -u");
|
|
64
|
+
if (uidOut.trim() === "0") {
|
|
65
|
+
this._hasSudo = true;
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
// Check if sudo works non-interactively (-n = no tty prompt)
|
|
69
|
+
const sudoResult = await ExecTools_1.ExecTools.safeExecWithCode("sudo -n true");
|
|
70
|
+
this._hasSudo = sudoResult.exitCode === 0;
|
|
71
|
+
return this._hasSudo;
|
|
72
|
+
}
|
|
73
|
+
async getStatus(name) {
|
|
74
|
+
const sudo = this.hasCustomConfig(name) ? "sudo " : "";
|
|
75
|
+
// Check if unit file exists — append .service suffix for reliable matching
|
|
76
|
+
const listResult = await ExecTools_1.ExecTools.safeExec(`${sudo}systemctl list-unit-files ${name}.service --no-legend`);
|
|
77
|
+
const installed = listResult.stdout.includes(`${name}.service`);
|
|
78
|
+
if (!installed) {
|
|
79
|
+
return {
|
|
80
|
+
name,
|
|
81
|
+
running: false,
|
|
82
|
+
enabled: false,
|
|
83
|
+
installed: false,
|
|
84
|
+
error: `Service "${name}" not found`,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
const [activeResult, enableResult] = await Promise.all([
|
|
88
|
+
ExecTools_1.ExecTools.safeExec(`${sudo}systemctl is-active ${name}`),
|
|
89
|
+
ExecTools_1.ExecTools.safeExec(`${sudo}systemctl is-enabled ${name}`),
|
|
90
|
+
]);
|
|
91
|
+
const activeStdout = activeResult.stdout.trim();
|
|
92
|
+
const enableStdout = enableResult.stdout.trim();
|
|
93
|
+
const running = activeStdout === "active";
|
|
94
|
+
const enabled = enableStdout === "enabled";
|
|
95
|
+
// Capture systemd "failed" state as an error the user can see
|
|
96
|
+
let error;
|
|
97
|
+
if (activeStdout === "failed") {
|
|
98
|
+
error = `Service "${name}" is in failed state — check the Journal panel for details.`;
|
|
99
|
+
}
|
|
100
|
+
// Try to get PID
|
|
101
|
+
let pid;
|
|
102
|
+
const pidResult = await ExecTools_1.ExecTools.safeExec(`${sudo}systemctl show ${name} --property=MainPID --value`);
|
|
103
|
+
const pidStr = pidResult.stdout.trim();
|
|
104
|
+
if (pidStr && pidStr !== "0") {
|
|
105
|
+
pid = parseInt(pidStr, 10);
|
|
106
|
+
}
|
|
107
|
+
return { name, running, enabled, installed, pid, error };
|
|
108
|
+
}
|
|
109
|
+
async perform(name, action) {
|
|
110
|
+
const sudo = "sudo ";
|
|
111
|
+
const cmd = `${sudo}systemctl ${action} ${name}`;
|
|
112
|
+
const result = await ExecTools_1.ExecTools.safeExecWithCode(cmd);
|
|
113
|
+
if (result.exitCode !== 0) {
|
|
114
|
+
return {
|
|
115
|
+
name,
|
|
116
|
+
running: false,
|
|
117
|
+
enabled: false,
|
|
118
|
+
installed: true,
|
|
119
|
+
error: `systemctl ${action} failed (code ${result.exitCode}): ${result.stderr.trim() || result.stdout.trim()}`,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
const status = await this.getStatus(name);
|
|
123
|
+
// After "start", verify the service is actually running
|
|
124
|
+
if (action === "start" && !status.running && !status.error) {
|
|
125
|
+
status.error = `Service "${name}" failed to start — check the Journal panel for details.`;
|
|
126
|
+
}
|
|
127
|
+
return status;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Build the systemd unit file content for a custom service.
|
|
131
|
+
*/
|
|
132
|
+
buildUnitContent(name, execStart) {
|
|
133
|
+
return `[Unit]
|
|
134
|
+
Description=ai server manager service (${name})
|
|
135
|
+
After=network.target
|
|
136
|
+
|
|
137
|
+
[Service]
|
|
138
|
+
Type=simple
|
|
139
|
+
ExecStart=${execStart}
|
|
140
|
+
Restart=on-failure
|
|
141
|
+
RestartSec=5
|
|
142
|
+
|
|
143
|
+
[Install]
|
|
144
|
+
WantedBy=multi-user.target
|
|
145
|
+
`;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Write the unit file and reload the daemon. Does NOT enable.
|
|
149
|
+
*/
|
|
150
|
+
async install(name, execStart) {
|
|
151
|
+
const sudo = "sudo ";
|
|
152
|
+
const unitPath = path.join(SYSTEM_UNIT_DIR, `${name}.service`);
|
|
153
|
+
const unitContent = this.buildUnitContent(name, execStart);
|
|
154
|
+
try {
|
|
155
|
+
if (this.hasCustomConfig(name)) {
|
|
156
|
+
const writeResult = await ExecTools_1.ExecTools.safeExecWithCode(`echo '${unitContent.replace(/'/g, "'\"'\"'")}' | sudo tee ${unitPath} > /dev/null`);
|
|
157
|
+
if (writeResult.exitCode !== 0) {
|
|
158
|
+
return {
|
|
159
|
+
name,
|
|
160
|
+
running: false,
|
|
161
|
+
enabled: false,
|
|
162
|
+
installed: false,
|
|
163
|
+
error: `Failed to write unit file: ${writeResult.stderr.trim()}`,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
fs.writeFileSync(unitPath, unitContent, "utf-8");
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
catch (err) {
|
|
172
|
+
return {
|
|
173
|
+
name,
|
|
174
|
+
running: false,
|
|
175
|
+
enabled: false,
|
|
176
|
+
installed: false,
|
|
177
|
+
error: `Failed to write unit file: ${err instanceof Error ? err.message : String(err)}`,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
const reloadResult = await ExecTools_1.ExecTools.safeExecWithCode(`${sudo}systemctl daemon-reload`);
|
|
181
|
+
if (reloadResult.exitCode !== 0) {
|
|
182
|
+
return {
|
|
183
|
+
name,
|
|
184
|
+
running: false,
|
|
185
|
+
enabled: false,
|
|
186
|
+
installed: true,
|
|
187
|
+
error: `systemctl daemon-reload failed: ${reloadResult.stderr.trim()}`,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
return this.getStatus(name);
|
|
191
|
+
}
|
|
192
|
+
async installAndEnable(name, execStart) {
|
|
193
|
+
const status = await this.install(name, execStart);
|
|
194
|
+
if (status.error)
|
|
195
|
+
return status;
|
|
196
|
+
const enableResult = await ExecTools_1.ExecTools.safeExecWithCode(`sudo systemctl enable ${name}`);
|
|
197
|
+
if (enableResult.exitCode !== 0) {
|
|
198
|
+
return {
|
|
199
|
+
name,
|
|
200
|
+
running: false,
|
|
201
|
+
enabled: false,
|
|
202
|
+
installed: true,
|
|
203
|
+
error: `systemctl enable failed: ${enableResult.stderr.trim()}`,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
return this.getStatus(name);
|
|
207
|
+
}
|
|
208
|
+
async uninstall(name) {
|
|
209
|
+
const sudo = this.hasCustomConfig(name) ? "sudo " : "";
|
|
210
|
+
const unitPath = path.join(SYSTEM_UNIT_DIR, `${name}.service`);
|
|
211
|
+
// Stop the service first (best-effort)
|
|
212
|
+
await ExecTools_1.ExecTools.safeExec(`${sudo}systemctl stop ${name}`);
|
|
213
|
+
// Disable the service (best-effort)
|
|
214
|
+
await ExecTools_1.ExecTools.safeExec(`${sudo}systemctl disable ${name}`);
|
|
215
|
+
// Remove unit file
|
|
216
|
+
try {
|
|
217
|
+
if (this.hasCustomConfig(name)) {
|
|
218
|
+
const rmResult = await ExecTools_1.ExecTools.safeExecWithCode(`sudo rm -f ${unitPath}`);
|
|
219
|
+
if (rmResult.exitCode !== 0) {
|
|
220
|
+
return { ok: false, error: `Failed to remove unit file: ${rmResult.stderr.trim()}` };
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
if (fs.existsSync(unitPath)) {
|
|
225
|
+
fs.unlinkSync(unitPath);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
catch (err) {
|
|
230
|
+
return { ok: false, error: `Failed to remove unit file: ${err instanceof Error ? err.message : String(err)}` };
|
|
231
|
+
}
|
|
232
|
+
// Reload systemd daemon
|
|
233
|
+
const reloadResult = await ExecTools_1.ExecTools.safeExecWithCode(`${sudo}systemctl daemon-reload`);
|
|
234
|
+
if (reloadResult.exitCode !== 0) {
|
|
235
|
+
return { ok: false, error: `systemctl daemon-reload failed: ${reloadResult.stderr.trim()}` };
|
|
236
|
+
}
|
|
237
|
+
return { ok: true };
|
|
238
|
+
}
|
|
239
|
+
async listAvailable() {
|
|
240
|
+
const { stdout } = await ExecTools_1.ExecTools.safeExec("systemctl list-unit-files --type=service --no-legend --no-pager --all");
|
|
241
|
+
const customNames = new Set(this.configManager.list().map((c) => c.name));
|
|
242
|
+
const names = [];
|
|
243
|
+
for (const line of stdout.split("\n")) {
|
|
244
|
+
const trimmed = line.trim();
|
|
245
|
+
if (!trimmed || trimmed.startsWith("UNIT") || trimmed.startsWith("Hint"))
|
|
246
|
+
continue;
|
|
247
|
+
const parts = trimmed.split(/\s+/);
|
|
248
|
+
const unitFile = parts[0];
|
|
249
|
+
if (!unitFile)
|
|
250
|
+
continue;
|
|
251
|
+
// Strip .service suffix
|
|
252
|
+
const name = unitFile.replace(/\.service$/, "");
|
|
253
|
+
// Skip custom services (have a config)
|
|
254
|
+
if (customNames.has(name))
|
|
255
|
+
continue;
|
|
256
|
+
names.push(name);
|
|
257
|
+
}
|
|
258
|
+
return names.sort();
|
|
259
|
+
}
|
|
260
|
+
async getJournal(name, count = 100) {
|
|
261
|
+
const sudo = this.hasCustomConfig(name) ? "sudo " : "";
|
|
262
|
+
// journalctl with verbose ISO timestamp for parsing
|
|
263
|
+
const result = await ExecTools_1.ExecTools.safeExec(`${sudo}journalctl -u ${name} --no-pager -n ${count} --output=short-iso 2>/dev/null || true`);
|
|
264
|
+
if (result.stderr && !result.stdout.trim()) {
|
|
265
|
+
return { error: result.stderr.trim() || `No journal found for "${name}"` };
|
|
266
|
+
}
|
|
267
|
+
const lines = [];
|
|
268
|
+
for (const raw of result.stdout.trim().split("\n")) {
|
|
269
|
+
const trimmed = raw.trim();
|
|
270
|
+
if (!trimmed)
|
|
271
|
+
continue;
|
|
272
|
+
// Parse "2026-07-16 12:34:56.789 +0300 hostname service[pid]: message"
|
|
273
|
+
// The timestamp is the first two token parts (date + time+offset)
|
|
274
|
+
const match = trimmed.match(/^(\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2}[^\s]*)\s+\S+\s+\S+:\s*(.*)$/);
|
|
275
|
+
if (match) {
|
|
276
|
+
lines.push({ timestamp: match[1], message: match[2] });
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
// Fallback: treat entire line as message with empty timestamp
|
|
280
|
+
lines.push({ timestamp: "", message: trimmed });
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return lines;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
exports.SystemctlController = SystemctlController;
|
|
287
|
+
//# sourceMappingURL=systemctlController.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"systemctlController.js","sourceRoot":"","sources":["../../../src/services/controllers/systemctlController.ts"],"names":[],"mappings":"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"}
|