@superdangerous/app-framework 4.9.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/LICENSE +21 -0
- package/README.md +652 -0
- package/dist/api/logsRouter.d.ts +20 -0
- package/dist/api/logsRouter.d.ts.map +1 -0
- package/dist/api/logsRouter.js +515 -0
- package/dist/api/logsRouter.js.map +1 -0
- package/dist/cli/dev-server.d.ts +7 -0
- package/dist/cli/dev-server.d.ts.map +1 -0
- package/dist/cli/dev-server.js +640 -0
- package/dist/cli/dev-server.js.map +1 -0
- package/dist/cli/index.d.ts +7 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +26 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/core/StandardServer.d.ts +129 -0
- package/dist/core/StandardServer.d.ts.map +1 -0
- package/dist/core/StandardServer.js +453 -0
- package/dist/core/StandardServer.js.map +1 -0
- package/dist/core/apiResponse.d.ts +69 -0
- package/dist/core/apiResponse.d.ts.map +1 -0
- package/dist/core/apiResponse.js +127 -0
- package/dist/core/apiResponse.js.map +1 -0
- package/dist/core/healthCheck.d.ts +160 -0
- package/dist/core/healthCheck.d.ts.map +1 -0
- package/dist/core/healthCheck.js +398 -0
- package/dist/core/healthCheck.js.map +1 -0
- package/dist/core/index.d.ts +40 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +40 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/logger.d.ts +117 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +826 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/portUtils.d.ts +71 -0
- package/dist/core/portUtils.d.ts.map +1 -0
- package/dist/core/portUtils.js +240 -0
- package/dist/core/portUtils.js.map +1 -0
- package/dist/core/storageService.d.ts +119 -0
- package/dist/core/storageService.d.ts.map +1 -0
- package/dist/core/storageService.js +405 -0
- package/dist/core/storageService.js.map +1 -0
- package/dist/desktop/bundler.d.ts +40 -0
- package/dist/desktop/bundler.d.ts.map +1 -0
- package/dist/desktop/bundler.js +176 -0
- package/dist/desktop/bundler.js.map +1 -0
- package/dist/desktop/index.d.ts +25 -0
- package/dist/desktop/index.d.ts.map +1 -0
- package/dist/desktop/index.js +15 -0
- package/dist/desktop/index.js.map +1 -0
- package/dist/desktop/native-modules.d.ts +66 -0
- package/dist/desktop/native-modules.d.ts.map +1 -0
- package/dist/desktop/native-modules.js +200 -0
- package/dist/desktop/native-modules.js.map +1 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +39 -0
- package/dist/index.js.map +1 -0
- package/dist/logging/LogCategories.d.ts +87 -0
- package/dist/logging/LogCategories.d.ts.map +1 -0
- package/dist/logging/LogCategories.js +205 -0
- package/dist/logging/LogCategories.js.map +1 -0
- package/dist/middleware/aiErrorHandler.d.ts +31 -0
- package/dist/middleware/aiErrorHandler.d.ts.map +1 -0
- package/dist/middleware/aiErrorHandler.js +181 -0
- package/dist/middleware/aiErrorHandler.js.map +1 -0
- package/dist/middleware/auth.d.ts +101 -0
- package/dist/middleware/auth.d.ts.map +1 -0
- package/dist/middleware/auth.js +230 -0
- package/dist/middleware/auth.js.map +1 -0
- package/dist/middleware/cors.d.ts +56 -0
- package/dist/middleware/cors.d.ts.map +1 -0
- package/dist/middleware/cors.js +123 -0
- package/dist/middleware/cors.js.map +1 -0
- package/dist/middleware/errorHandler.d.ts +13 -0
- package/dist/middleware/errorHandler.d.ts.map +1 -0
- package/dist/middleware/errorHandler.js +85 -0
- package/dist/middleware/errorHandler.js.map +1 -0
- package/dist/middleware/fileUpload.d.ts +62 -0
- package/dist/middleware/fileUpload.d.ts.map +1 -0
- package/dist/middleware/fileUpload.js +175 -0
- package/dist/middleware/fileUpload.js.map +1 -0
- package/dist/middleware/health.d.ts +48 -0
- package/dist/middleware/health.d.ts.map +1 -0
- package/dist/middleware/health.js +143 -0
- package/dist/middleware/health.js.map +1 -0
- package/dist/middleware/index.d.ts +20 -0
- package/dist/middleware/index.d.ts.map +1 -0
- package/dist/middleware/index.js +18 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/middleware/openapi.d.ts +64 -0
- package/dist/middleware/openapi.d.ts.map +1 -0
- package/dist/middleware/openapi.js +258 -0
- package/dist/middleware/openapi.js.map +1 -0
- package/dist/middleware/requestLogging.d.ts +22 -0
- package/dist/middleware/requestLogging.d.ts.map +1 -0
- package/dist/middleware/requestLogging.js +61 -0
- package/dist/middleware/requestLogging.js.map +1 -0
- package/dist/middleware/session.d.ts +84 -0
- package/dist/middleware/session.d.ts.map +1 -0
- package/dist/middleware/session.js +189 -0
- package/dist/middleware/session.js.map +1 -0
- package/dist/middleware/validation.d.ts +1337 -0
- package/dist/middleware/validation.d.ts.map +1 -0
- package/dist/middleware/validation.js +483 -0
- package/dist/middleware/validation.js.map +1 -0
- package/dist/services/aiService.d.ts +180 -0
- package/dist/services/aiService.d.ts.map +1 -0
- package/dist/services/aiService.js +547 -0
- package/dist/services/aiService.js.map +1 -0
- package/dist/services/conversationStorage.d.ts +38 -0
- package/dist/services/conversationStorage.d.ts.map +1 -0
- package/dist/services/conversationStorage.js +158 -0
- package/dist/services/conversationStorage.js.map +1 -0
- package/dist/services/crossPlatformBuffer.d.ts +84 -0
- package/dist/services/crossPlatformBuffer.d.ts.map +1 -0
- package/dist/services/crossPlatformBuffer.js +246 -0
- package/dist/services/crossPlatformBuffer.js.map +1 -0
- package/dist/services/index.d.ts +17 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +18 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/networkService.d.ts +81 -0
- package/dist/services/networkService.d.ts.map +1 -0
- package/dist/services/networkService.js +268 -0
- package/dist/services/networkService.js.map +1 -0
- package/dist/services/queueService.d.ts +112 -0
- package/dist/services/queueService.d.ts.map +1 -0
- package/dist/services/queueService.js +338 -0
- package/dist/services/queueService.js.map +1 -0
- package/dist/services/settingsService.d.ts +135 -0
- package/dist/services/settingsService.d.ts.map +1 -0
- package/dist/services/settingsService.js +425 -0
- package/dist/services/settingsService.js.map +1 -0
- package/dist/services/systemMonitor.d.ts +208 -0
- package/dist/services/systemMonitor.d.ts.map +1 -0
- package/dist/services/systemMonitor.js +693 -0
- package/dist/services/systemMonitor.js.map +1 -0
- package/dist/services/updateService.d.ts +78 -0
- package/dist/services/updateService.d.ts.map +1 -0
- package/dist/services/updateService.js +252 -0
- package/dist/services/updateService.js.map +1 -0
- package/dist/services/websocketEvents.d.ts +372 -0
- package/dist/services/websocketEvents.d.ts.map +1 -0
- package/dist/services/websocketEvents.js +338 -0
- package/dist/services/websocketEvents.js.map +1 -0
- package/dist/services/websocketServer.d.ts +80 -0
- package/dist/services/websocketServer.d.ts.map +1 -0
- package/dist/services/websocketServer.js +299 -0
- package/dist/services/websocketServer.js.map +1 -0
- package/dist/settings/SettingsSchema.d.ts +151 -0
- package/dist/settings/SettingsSchema.d.ts.map +1 -0
- package/dist/settings/SettingsSchema.js +424 -0
- package/dist/settings/SettingsSchema.js.map +1 -0
- package/dist/testing/TestServer.d.ts +69 -0
- package/dist/testing/TestServer.d.ts.map +1 -0
- package/dist/testing/TestServer.js +250 -0
- package/dist/testing/TestServer.js.map +1 -0
- package/dist/types/index.d.ts +137 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +5 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/appPaths.d.ts +74 -0
- package/dist/utils/appPaths.d.ts.map +1 -0
- package/dist/utils/appPaths.js +162 -0
- package/dist/utils/appPaths.js.map +1 -0
- package/dist/utils/fs-utils.d.ts +50 -0
- package/dist/utils/fs-utils.d.ts.map +1 -0
- package/dist/utils/fs-utils.js +114 -0
- package/dist/utils/fs-utils.js.map +1 -0
- package/dist/utils/index.d.ts +12 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +10 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/standardConfig.d.ts +61 -0
- package/dist/utils/standardConfig.d.ts.map +1 -0
- package/dist/utils/standardConfig.js +109 -0
- package/dist/utils/standardConfig.js.map +1 -0
- package/dist/utils/startupBanner.d.ts +34 -0
- package/dist/utils/startupBanner.d.ts.map +1 -0
- package/dist/utils/startupBanner.js +169 -0
- package/dist/utils/startupBanner.js.map +1 -0
- package/dist/utils/startupLogger.d.ts +45 -0
- package/dist/utils/startupLogger.d.ts.map +1 -0
- package/dist/utils/startupLogger.js +200 -0
- package/dist/utils/startupLogger.js.map +1 -0
- package/package.json +151 -0
- package/src/api/logsRouter.ts +600 -0
- package/src/cli/dev-server.ts +803 -0
- package/src/cli/index.ts +31 -0
- package/src/core/StandardServer.ts +587 -0
- package/src/core/apiResponse.ts +202 -0
- package/src/core/healthCheck.ts +565 -0
- package/src/core/index.ts +80 -0
- package/src/core/logger.ts +1092 -0
- package/src/core/portUtils.ts +319 -0
- package/src/core/storageService.ts +595 -0
- package/src/desktop/bundler.ts +271 -0
- package/src/desktop/index.ts +18 -0
- package/src/desktop/native-modules.ts +289 -0
- package/src/index.ts +142 -0
- package/src/logging/LogCategories.ts +302 -0
- package/src/middleware/aiErrorHandler.ts +278 -0
- package/src/middleware/auth.ts +329 -0
- package/src/middleware/cors.ts +187 -0
- package/src/middleware/errorHandler.ts +103 -0
- package/src/middleware/fileUpload.ts +252 -0
- package/src/middleware/health.ts +206 -0
- package/src/middleware/index.ts +71 -0
- package/src/middleware/openapi.ts +305 -0
- package/src/middleware/requestLogging.ts +92 -0
- package/src/middleware/session.ts +238 -0
- package/src/middleware/validation.ts +603 -0
- package/src/services/aiService.ts +789 -0
- package/src/services/conversationStorage.ts +232 -0
- package/src/services/crossPlatformBuffer.ts +341 -0
- package/src/services/index.ts +47 -0
- package/src/services/networkService.ts +351 -0
- package/src/services/queueService.ts +446 -0
- package/src/services/settingsService.ts +549 -0
- package/src/services/systemMonitor.ts +936 -0
- package/src/services/updateService.ts +334 -0
- package/src/services/websocketEvents.ts +409 -0
- package/src/services/websocketServer.ts +394 -0
- package/src/settings/SettingsSchema.ts +664 -0
- package/src/testing/TestServer.ts +312 -0
- package/src/types/index.ts +154 -0
- package/src/utils/appPaths.ts +196 -0
- package/src/utils/fs-utils.ts +130 -0
- package/src/utils/index.ts +15 -0
- package/src/utils/standardConfig.ts +178 -0
- package/src/utils/startupBanner.ts +287 -0
- package/src/utils/startupLogger.ts +268 -0
- package/ui/dist/index.d.mts +1221 -0
- package/ui/dist/index.d.ts +1221 -0
- package/ui/dist/index.js +73 -0
- package/ui/dist/index.js.map +1 -0
- package/ui/dist/index.mjs +73 -0
- package/ui/dist/index.mjs.map +1 -0
|
@@ -0,0 +1,693 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enhanced System Monitor Service
|
|
3
|
+
* Provides comprehensive system health and performance metrics
|
|
4
|
+
*/
|
|
5
|
+
import os from "os";
|
|
6
|
+
import fs from "fs";
|
|
7
|
+
import { promisify } from "util";
|
|
8
|
+
import { exec } from "child_process";
|
|
9
|
+
import { createLogger } from "../core/index.js";
|
|
10
|
+
const execAsync = promisify(exec);
|
|
11
|
+
const logger = createLogger("SystemMonitor");
|
|
12
|
+
class SystemMonitor {
|
|
13
|
+
cpuUsageHistory = [];
|
|
14
|
+
lastCPUInfo = null;
|
|
15
|
+
diskIOCache = new Map();
|
|
16
|
+
/**
|
|
17
|
+
* Get comprehensive system health metrics
|
|
18
|
+
*/
|
|
19
|
+
async getSystemHealth() {
|
|
20
|
+
const [cpu, memory, disk, system, network] = await Promise.all([
|
|
21
|
+
this.getCPUInfo(),
|
|
22
|
+
this.getMemoryInfo(),
|
|
23
|
+
this.getDiskInfo(),
|
|
24
|
+
this.getSystemInfo(),
|
|
25
|
+
this.getNetworkInfo(),
|
|
26
|
+
]);
|
|
27
|
+
return {
|
|
28
|
+
cpu,
|
|
29
|
+
memory,
|
|
30
|
+
disk,
|
|
31
|
+
system,
|
|
32
|
+
network,
|
|
33
|
+
timestamp: new Date(),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Get CPU information including temperature
|
|
38
|
+
*/
|
|
39
|
+
async getCPUInfo() {
|
|
40
|
+
const cpus = os.cpus();
|
|
41
|
+
const model = cpus[0]?.model || "Unknown";
|
|
42
|
+
const cores = cpus.length;
|
|
43
|
+
const speed = cpus[0]?.speed || 0;
|
|
44
|
+
const loadAverage = os.loadavg();
|
|
45
|
+
// Calculate CPU usage
|
|
46
|
+
const usage = await this.calculateCPUUsage();
|
|
47
|
+
// Try to get CPU temperature
|
|
48
|
+
const temperature = await this.getCPUTemperature();
|
|
49
|
+
return {
|
|
50
|
+
usage,
|
|
51
|
+
temperature,
|
|
52
|
+
cores,
|
|
53
|
+
model,
|
|
54
|
+
speed,
|
|
55
|
+
loadAverage,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Calculate CPU usage percentage
|
|
60
|
+
*/
|
|
61
|
+
async calculateCPUUsage() {
|
|
62
|
+
const cpus = os.cpus();
|
|
63
|
+
let totalIdle = 0;
|
|
64
|
+
let totalTick = 0;
|
|
65
|
+
cpus.forEach((cpu) => {
|
|
66
|
+
for (const type in cpu.times) {
|
|
67
|
+
totalTick += cpu.times[type];
|
|
68
|
+
}
|
|
69
|
+
totalIdle += cpu.times.idle;
|
|
70
|
+
});
|
|
71
|
+
if (this.lastCPUInfo) {
|
|
72
|
+
const idleDiff = totalIdle - this.lastCPUInfo.idle;
|
|
73
|
+
const totalDiff = totalTick - this.lastCPUInfo.total;
|
|
74
|
+
const usage = Math.round(100 - (100 * idleDiff) / totalDiff);
|
|
75
|
+
this.cpuUsageHistory.push(usage);
|
|
76
|
+
if (this.cpuUsageHistory.length > 60) {
|
|
77
|
+
this.cpuUsageHistory.shift();
|
|
78
|
+
}
|
|
79
|
+
this.lastCPUInfo = { idle: totalIdle, total: totalTick };
|
|
80
|
+
return usage;
|
|
81
|
+
}
|
|
82
|
+
this.lastCPUInfo = { idle: totalIdle, total: totalTick };
|
|
83
|
+
return 0;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Get CPU temperature (platform-specific)
|
|
87
|
+
*/
|
|
88
|
+
async getCPUTemperature() {
|
|
89
|
+
const platform = process.platform;
|
|
90
|
+
try {
|
|
91
|
+
if (platform === "darwin") {
|
|
92
|
+
// macOS - try using osx-temperature-sensor
|
|
93
|
+
const { stdout } = await execAsync('sysctl -n machdep.xcpm.cpu_thermal_level 2>/dev/null || echo ""');
|
|
94
|
+
if (stdout.trim()) {
|
|
95
|
+
return parseFloat(stdout.trim());
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
else if (platform === "linux") {
|
|
99
|
+
// Linux - read from thermal zone
|
|
100
|
+
const thermalZone = "/sys/class/thermal/thermal_zone0/temp";
|
|
101
|
+
if (fs.existsSync(thermalZone)) {
|
|
102
|
+
const temp = fs.readFileSync(thermalZone, "utf8");
|
|
103
|
+
return parseInt(temp) / 1000; // Convert from millidegrees
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
else if (platform === "win32") {
|
|
107
|
+
// Windows - use wmic
|
|
108
|
+
const { stdout } = await execAsync("wmic /namespace:\\\\root\\wmi PATH MSAcpi_ThermalZoneTemperature get CurrentTemperature /value");
|
|
109
|
+
const match = stdout.match(/CurrentTemperature=(\d+)/);
|
|
110
|
+
if (match) {
|
|
111
|
+
// Convert from tenths of Kelvin to Celsius
|
|
112
|
+
return (parseInt(match[1]) - 2732) / 10;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
catch (_error) {
|
|
117
|
+
logger.debug("Could not get CPU temperature:", _error);
|
|
118
|
+
}
|
|
119
|
+
return undefined;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Get memory information including swap and detailed breakdown
|
|
123
|
+
*/
|
|
124
|
+
async getMemoryInfo() {
|
|
125
|
+
const totalMem = os.totalmem();
|
|
126
|
+
const freeMem = os.freemem();
|
|
127
|
+
const usedMem = totalMem - freeMem;
|
|
128
|
+
const percentage = Math.round((usedMem / totalMem) * 100);
|
|
129
|
+
const memInfo = {
|
|
130
|
+
total: totalMem,
|
|
131
|
+
used: usedMem,
|
|
132
|
+
free: freeMem,
|
|
133
|
+
percentage,
|
|
134
|
+
};
|
|
135
|
+
// Add process memory usage
|
|
136
|
+
const memUsage = process.memoryUsage();
|
|
137
|
+
memInfo.process = {
|
|
138
|
+
rss: memUsage.rss,
|
|
139
|
+
heapTotal: memUsage.heapTotal,
|
|
140
|
+
heapUsed: memUsage.heapUsed,
|
|
141
|
+
external: memUsage.external,
|
|
142
|
+
arrayBuffers: memUsage.arrayBuffers || 0,
|
|
143
|
+
};
|
|
144
|
+
// Try to get detailed memory information
|
|
145
|
+
const detailed = await this.getDetailedMemoryInfo();
|
|
146
|
+
if (detailed) {
|
|
147
|
+
Object.assign(memInfo, detailed);
|
|
148
|
+
}
|
|
149
|
+
// Try to get swap information
|
|
150
|
+
const swap = await this.getSwapInfo();
|
|
151
|
+
if (swap) {
|
|
152
|
+
memInfo.swap = {
|
|
153
|
+
...swap,
|
|
154
|
+
percentage: swap.total > 0 ? Math.round((swap.used / swap.total) * 100) : 0,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
return memInfo;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Get detailed memory breakdown (Linux only)
|
|
161
|
+
*/
|
|
162
|
+
async getDetailedMemoryInfo() {
|
|
163
|
+
const platform = process.platform;
|
|
164
|
+
if (platform !== "linux") {
|
|
165
|
+
return undefined;
|
|
166
|
+
}
|
|
167
|
+
try {
|
|
168
|
+
const { stdout } = await execAsync("cat /proc/meminfo");
|
|
169
|
+
const lines = stdout.split("\n");
|
|
170
|
+
const meminfo = {};
|
|
171
|
+
for (const line of lines) {
|
|
172
|
+
const match = line.match(/^(\w+):\s+(\d+)\s+kB/);
|
|
173
|
+
if (match) {
|
|
174
|
+
meminfo[match[1]] = parseInt(match[2]) * 1024; // Convert to bytes
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
const result = {};
|
|
178
|
+
// Available memory
|
|
179
|
+
if (meminfo.MemAvailable) {
|
|
180
|
+
result.available = meminfo.MemAvailable;
|
|
181
|
+
}
|
|
182
|
+
// Active/Inactive
|
|
183
|
+
if (meminfo.Active)
|
|
184
|
+
result.active = meminfo.Active;
|
|
185
|
+
if (meminfo.Inactive)
|
|
186
|
+
result.inactive = meminfo.Inactive;
|
|
187
|
+
// Buffers/Cached
|
|
188
|
+
if (meminfo.Buffers)
|
|
189
|
+
result.buffers = meminfo.Buffers;
|
|
190
|
+
if (meminfo.Cached)
|
|
191
|
+
result.cached = meminfo.Cached;
|
|
192
|
+
// Detailed breakdown
|
|
193
|
+
if (meminfo.Slab || meminfo.KernelStack || meminfo.PageTables) {
|
|
194
|
+
result.breakdown = {
|
|
195
|
+
apps: meminfo.MemTotal -
|
|
196
|
+
meminfo.MemFree -
|
|
197
|
+
meminfo.Buffers -
|
|
198
|
+
meminfo.Cached || 0,
|
|
199
|
+
pageCache: meminfo.Cached || 0,
|
|
200
|
+
buffers: meminfo.Buffers || 0,
|
|
201
|
+
slab: meminfo.Slab || 0,
|
|
202
|
+
kernelStack: meminfo.KernelStack || 0,
|
|
203
|
+
pageTables: meminfo.PageTables || 0,
|
|
204
|
+
vmallocUsed: meminfo.VmallocUsed || 0,
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
return result;
|
|
208
|
+
}
|
|
209
|
+
catch (_error) {
|
|
210
|
+
logger.debug("Could not get detailed memory info:", _error);
|
|
211
|
+
return undefined;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Get swap memory information
|
|
216
|
+
*/
|
|
217
|
+
async getSwapInfo() {
|
|
218
|
+
const platform = process.platform;
|
|
219
|
+
try {
|
|
220
|
+
if (platform === "linux") {
|
|
221
|
+
const { stdout } = await execAsync("free -b | grep Swap");
|
|
222
|
+
const parts = stdout.trim().split(/\s+/);
|
|
223
|
+
if (parts.length >= 3) {
|
|
224
|
+
return {
|
|
225
|
+
total: parseInt(parts[1]),
|
|
226
|
+
used: parseInt(parts[2]),
|
|
227
|
+
free: parseInt(parts[3]),
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
else if (platform === "darwin") {
|
|
232
|
+
const { stdout } = await execAsync("sysctl vm.swapusage");
|
|
233
|
+
const match = stdout.match(/total = ([\d.]+)M.*used = ([\d.]+)M.*free = ([\d.]+)M/);
|
|
234
|
+
if (match) {
|
|
235
|
+
return {
|
|
236
|
+
total: parseFloat(match[1]) * 1024 * 1024,
|
|
237
|
+
used: parseFloat(match[2]) * 1024 * 1024,
|
|
238
|
+
free: parseFloat(match[3]) * 1024 * 1024,
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
catch (_error) {
|
|
244
|
+
logger.debug("Could not get swap information:", _error);
|
|
245
|
+
}
|
|
246
|
+
return undefined;
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Get disk information including I/O stats
|
|
250
|
+
*/
|
|
251
|
+
async getDiskInfo() {
|
|
252
|
+
const platform = process.platform;
|
|
253
|
+
let diskInfo = {
|
|
254
|
+
total: 0,
|
|
255
|
+
used: 0,
|
|
256
|
+
free: 0,
|
|
257
|
+
percentage: 0,
|
|
258
|
+
};
|
|
259
|
+
try {
|
|
260
|
+
if (platform === "darwin" || platform === "linux") {
|
|
261
|
+
const { stdout } = await execAsync("df -k / | tail -1");
|
|
262
|
+
const parts = stdout.trim().split(/\s+/);
|
|
263
|
+
if (parts.length >= 4) {
|
|
264
|
+
const total = parseInt(parts[1]) * 1024;
|
|
265
|
+
const used = parseInt(parts[2]) * 1024;
|
|
266
|
+
const free = parseInt(parts[3]) * 1024;
|
|
267
|
+
const percentage = Math.round((used / total) * 100);
|
|
268
|
+
diskInfo = { total, used, free, percentage };
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
else if (platform === "win32") {
|
|
272
|
+
const { stdout } = await execAsync("wmic logicaldisk get size,freespace /value");
|
|
273
|
+
const lines = stdout.trim().split("\n");
|
|
274
|
+
let total = 0, free = 0;
|
|
275
|
+
lines.forEach((line) => {
|
|
276
|
+
if (line.startsWith("FreeSpace=")) {
|
|
277
|
+
const value = line.split("=")[1];
|
|
278
|
+
if (value)
|
|
279
|
+
free += parseInt(value);
|
|
280
|
+
}
|
|
281
|
+
else if (line.startsWith("Size=")) {
|
|
282
|
+
const value = line.split("=")[1];
|
|
283
|
+
if (value)
|
|
284
|
+
total += parseInt(value);
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
const used = total - free;
|
|
288
|
+
const percentage = total > 0 ? Math.round((used / total) * 100) : 0;
|
|
289
|
+
diskInfo = { total, used, free, percentage };
|
|
290
|
+
}
|
|
291
|
+
// Get I/O stats
|
|
292
|
+
const io = await this.getDiskIOStats();
|
|
293
|
+
if (io) {
|
|
294
|
+
diskInfo.io = io;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
catch (_error) {
|
|
298
|
+
logger.debug("Could not get disk information:", _error);
|
|
299
|
+
}
|
|
300
|
+
return diskInfo;
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Get disk I/O statistics
|
|
304
|
+
*/
|
|
305
|
+
async getDiskIOStats() {
|
|
306
|
+
const platform = process.platform;
|
|
307
|
+
try {
|
|
308
|
+
if (platform === "linux") {
|
|
309
|
+
const { stdout } = await execAsync('cat /proc/diskstats | grep -E "sda |nvme0n1 " | head -1');
|
|
310
|
+
const parts = stdout.trim().split(/\s+/);
|
|
311
|
+
if (parts.length >= 10) {
|
|
312
|
+
const current = {
|
|
313
|
+
readOps: parseInt(parts[3]),
|
|
314
|
+
readBytes: parseInt(parts[5]) * 512,
|
|
315
|
+
writeOps: parseInt(parts[7]),
|
|
316
|
+
writeBytes: parseInt(parts[9]) * 512,
|
|
317
|
+
};
|
|
318
|
+
// Calculate rate if we have previous data
|
|
319
|
+
const cacheKey = "diskio";
|
|
320
|
+
const previous = this.diskIOCache.get(cacheKey);
|
|
321
|
+
if (previous) {
|
|
322
|
+
const timeDiff = Date.now() - previous.timestamp;
|
|
323
|
+
const rateFactor = 1000 / timeDiff; // Convert to per second
|
|
324
|
+
const io = {
|
|
325
|
+
readBytes: Math.round((current.readBytes - previous.readBytes) * rateFactor),
|
|
326
|
+
writeBytes: Math.round((current.writeBytes - previous.writeBytes) * rateFactor),
|
|
327
|
+
readOps: Math.round((current.readOps - previous.readOps) * rateFactor),
|
|
328
|
+
writeOps: Math.round((current.writeOps - previous.writeOps) * rateFactor),
|
|
329
|
+
};
|
|
330
|
+
this.diskIOCache.set(cacheKey, {
|
|
331
|
+
...current,
|
|
332
|
+
timestamp: Date.now(),
|
|
333
|
+
});
|
|
334
|
+
return io;
|
|
335
|
+
}
|
|
336
|
+
this.diskIOCache.set(cacheKey, { ...current, timestamp: Date.now() });
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
else if (platform === "darwin") {
|
|
340
|
+
const { stdout } = await execAsync("iostat -d -w 1 -c 2 | tail -1");
|
|
341
|
+
const parts = stdout.trim().split(/\s+/);
|
|
342
|
+
if (parts.length >= 3) {
|
|
343
|
+
return {
|
|
344
|
+
readBytes: parseFloat(parts[0]) * 1024,
|
|
345
|
+
writeBytes: parseFloat(parts[1]) * 1024,
|
|
346
|
+
readOps: 0,
|
|
347
|
+
writeOps: 0,
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
catch (_error) {
|
|
353
|
+
logger.debug("Could not get disk I/O statistics:", _error);
|
|
354
|
+
}
|
|
355
|
+
return undefined;
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Get system information
|
|
359
|
+
*/
|
|
360
|
+
async getSystemInfo() {
|
|
361
|
+
const platform = process.platform;
|
|
362
|
+
const arch = process.arch;
|
|
363
|
+
const version = os.release();
|
|
364
|
+
const hostname = os.hostname();
|
|
365
|
+
const uptime = os.uptime();
|
|
366
|
+
const bootTime = new Date(Date.now() - uptime * 1000);
|
|
367
|
+
let kernel = version;
|
|
368
|
+
// Try to get more detailed kernel info
|
|
369
|
+
try {
|
|
370
|
+
if (platform === "linux" || platform === "darwin") {
|
|
371
|
+
const { stdout } = await execAsync("uname -r");
|
|
372
|
+
kernel = stdout.trim();
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
catch {
|
|
376
|
+
// Use default
|
|
377
|
+
}
|
|
378
|
+
return {
|
|
379
|
+
platform,
|
|
380
|
+
arch,
|
|
381
|
+
version,
|
|
382
|
+
kernel,
|
|
383
|
+
hostname,
|
|
384
|
+
uptime,
|
|
385
|
+
bootTime,
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* Get network information
|
|
390
|
+
*/
|
|
391
|
+
async getNetworkInfo() {
|
|
392
|
+
const interfaces = await this.getNetworkInterfaces();
|
|
393
|
+
const connections = await this.getNetworkConnections();
|
|
394
|
+
return {
|
|
395
|
+
interfaces,
|
|
396
|
+
connections,
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* Get detailed network interface information
|
|
401
|
+
*/
|
|
402
|
+
async getNetworkInterfaces() {
|
|
403
|
+
const interfaces = os.networkInterfaces();
|
|
404
|
+
const result = [];
|
|
405
|
+
for (const [name, addresses] of Object.entries(interfaces)) {
|
|
406
|
+
if (!addresses)
|
|
407
|
+
continue;
|
|
408
|
+
const ipv4Addresses = addresses
|
|
409
|
+
.filter((addr) => addr.family === "IPv4")
|
|
410
|
+
.map((addr) => addr.address);
|
|
411
|
+
if (ipv4Addresses.length > 0) {
|
|
412
|
+
const interfaceInfo = {
|
|
413
|
+
name,
|
|
414
|
+
addresses: ipv4Addresses,
|
|
415
|
+
mac: addresses[0]?.mac || "00:00:00:00:00:00",
|
|
416
|
+
};
|
|
417
|
+
// Try to get interface statistics
|
|
418
|
+
const stats = await this.getInterfaceStats(name);
|
|
419
|
+
if (stats) {
|
|
420
|
+
interfaceInfo.stats = stats;
|
|
421
|
+
}
|
|
422
|
+
result.push(interfaceInfo);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
return result;
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* Get network interface statistics
|
|
429
|
+
*/
|
|
430
|
+
async getInterfaceStats(interfaceName) {
|
|
431
|
+
const platform = process.platform;
|
|
432
|
+
try {
|
|
433
|
+
if (platform === "linux") {
|
|
434
|
+
const statsFile = `/sys/class/net/${interfaceName}/statistics`;
|
|
435
|
+
if (fs.existsSync(statsFile)) {
|
|
436
|
+
const readFile = (file) => {
|
|
437
|
+
try {
|
|
438
|
+
return parseInt(fs.readFileSync(`${statsFile}/${file}`, "utf8").trim());
|
|
439
|
+
}
|
|
440
|
+
catch {
|
|
441
|
+
return 0;
|
|
442
|
+
}
|
|
443
|
+
};
|
|
444
|
+
return {
|
|
445
|
+
rxBytes: readFile("rx_bytes"),
|
|
446
|
+
txBytes: readFile("tx_bytes"),
|
|
447
|
+
rxPackets: readFile("rx_packets"),
|
|
448
|
+
txPackets: readFile("tx_packets"),
|
|
449
|
+
rxErrors: readFile("rx_errors"),
|
|
450
|
+
txErrors: readFile("tx_errors"),
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
else if (platform === "darwin") {
|
|
455
|
+
const { stdout } = await execAsync(`netstat -ibn | grep -A 1 "^${interfaceName}"`);
|
|
456
|
+
const lines = stdout.trim().split("\n");
|
|
457
|
+
if (lines.length >= 2) {
|
|
458
|
+
const parts = lines[1].trim().split(/\s+/);
|
|
459
|
+
if (parts.length >= 10) {
|
|
460
|
+
return {
|
|
461
|
+
rxPackets: parseInt(parts[4]),
|
|
462
|
+
rxErrors: parseInt(parts[5]),
|
|
463
|
+
rxBytes: parseInt(parts[6]),
|
|
464
|
+
txPackets: parseInt(parts[7]),
|
|
465
|
+
txErrors: parseInt(parts[8]),
|
|
466
|
+
txBytes: parseInt(parts[9]),
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
catch (_error) {
|
|
473
|
+
logger.debug(`Could not get stats for interface ${interfaceName}:`, _error);
|
|
474
|
+
}
|
|
475
|
+
return undefined;
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Get detailed network statistics with bandwidth usage
|
|
479
|
+
*/
|
|
480
|
+
async getNetworkStatistics() {
|
|
481
|
+
const interfaces = await this.getNetworkInterfaces();
|
|
482
|
+
let totalBytesReceived = 0;
|
|
483
|
+
let totalBytesSent = 0;
|
|
484
|
+
let totalPacketsReceived = 0;
|
|
485
|
+
let totalPacketsSent = 0;
|
|
486
|
+
// Sum up statistics from all interfaces
|
|
487
|
+
for (const iface of interfaces) {
|
|
488
|
+
if (iface.stats) {
|
|
489
|
+
totalBytesReceived += iface.stats.rxBytes || 0;
|
|
490
|
+
totalBytesSent += iface.stats.txBytes || 0;
|
|
491
|
+
totalPacketsReceived += iface.stats.rxPackets || 0;
|
|
492
|
+
totalPacketsSent += iface.stats.txPackets || 0;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
const connections = await this.getNetworkConnections();
|
|
496
|
+
// Calculate bandwidth if we have previous measurements
|
|
497
|
+
const bandwidth = await this.calculateBandwidth(totalBytesReceived, totalBytesSent);
|
|
498
|
+
return {
|
|
499
|
+
interfaces,
|
|
500
|
+
totalBytesReceived,
|
|
501
|
+
totalBytesSent,
|
|
502
|
+
totalPacketsReceived,
|
|
503
|
+
totalPacketsSent,
|
|
504
|
+
connections,
|
|
505
|
+
bandwidth,
|
|
506
|
+
};
|
|
507
|
+
}
|
|
508
|
+
/**
|
|
509
|
+
* Calculate bandwidth based on byte counters
|
|
510
|
+
*/
|
|
511
|
+
lastNetworkMeasurement;
|
|
512
|
+
async calculateBandwidth(currentBytesReceived, currentBytesSent) {
|
|
513
|
+
const now = Date.now();
|
|
514
|
+
if (this.lastNetworkMeasurement) {
|
|
515
|
+
const timeDiff = (now - this.lastNetworkMeasurement.timestamp) / 1000; // seconds
|
|
516
|
+
if (timeDiff > 0) {
|
|
517
|
+
const download = (currentBytesReceived - this.lastNetworkMeasurement.bytesReceived) /
|
|
518
|
+
timeDiff;
|
|
519
|
+
const upload = (currentBytesSent - this.lastNetworkMeasurement.bytesSent) / timeDiff;
|
|
520
|
+
this.lastNetworkMeasurement = {
|
|
521
|
+
timestamp: now,
|
|
522
|
+
bytesReceived: currentBytesReceived,
|
|
523
|
+
bytesSent: currentBytesSent,
|
|
524
|
+
};
|
|
525
|
+
return {
|
|
526
|
+
download: Math.max(0, download),
|
|
527
|
+
upload: Math.max(0, upload),
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
else {
|
|
532
|
+
// First measurement
|
|
533
|
+
this.lastNetworkMeasurement = {
|
|
534
|
+
timestamp: now,
|
|
535
|
+
bytesReceived: currentBytesReceived,
|
|
536
|
+
bytesSent: currentBytesSent,
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
return undefined;
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
542
|
+
* Get active network connections by state
|
|
543
|
+
*/
|
|
544
|
+
async getNetworkConnectionsByState() {
|
|
545
|
+
const platform = process.platform;
|
|
546
|
+
try {
|
|
547
|
+
let established = 0;
|
|
548
|
+
let listening = 0;
|
|
549
|
+
let timeWait = 0;
|
|
550
|
+
let closeWait = 0;
|
|
551
|
+
if (platform === "linux") {
|
|
552
|
+
const { stdout } = await execAsync("ss -tan");
|
|
553
|
+
const lines = stdout.split("\n").slice(1); // Skip header
|
|
554
|
+
for (const line of lines) {
|
|
555
|
+
if (line.includes("ESTAB"))
|
|
556
|
+
established++;
|
|
557
|
+
else if (line.includes("LISTEN"))
|
|
558
|
+
listening++;
|
|
559
|
+
else if (line.includes("TIME-WAIT"))
|
|
560
|
+
timeWait++;
|
|
561
|
+
else if (line.includes("CLOSE-WAIT"))
|
|
562
|
+
closeWait++;
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
else if (platform === "darwin" || platform === "win32") {
|
|
566
|
+
const { stdout } = await execAsync("netstat -an");
|
|
567
|
+
const lines = stdout.split("\n");
|
|
568
|
+
for (const line of lines) {
|
|
569
|
+
if (line.includes("ESTABLISHED"))
|
|
570
|
+
established++;
|
|
571
|
+
else if (line.includes("LISTEN"))
|
|
572
|
+
listening++;
|
|
573
|
+
else if (line.includes("TIME_WAIT"))
|
|
574
|
+
timeWait++;
|
|
575
|
+
else if (line.includes("CLOSE_WAIT"))
|
|
576
|
+
closeWait++;
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
return {
|
|
580
|
+
established,
|
|
581
|
+
listening,
|
|
582
|
+
timeWait,
|
|
583
|
+
closeWait,
|
|
584
|
+
total: established + listening + timeWait + closeWait,
|
|
585
|
+
};
|
|
586
|
+
}
|
|
587
|
+
catch (_error) {
|
|
588
|
+
logger.debug("Could not get network connections by state:", _error);
|
|
589
|
+
return {
|
|
590
|
+
established: 0,
|
|
591
|
+
listening: 0,
|
|
592
|
+
timeWait: 0,
|
|
593
|
+
closeWait: 0,
|
|
594
|
+
total: 0,
|
|
595
|
+
};
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
/**
|
|
599
|
+
* Get number of network connections
|
|
600
|
+
*/
|
|
601
|
+
async getNetworkConnections() {
|
|
602
|
+
try {
|
|
603
|
+
const platform = process.platform;
|
|
604
|
+
let command = "";
|
|
605
|
+
if (platform === "linux") {
|
|
606
|
+
command = "ss -tun | tail -n +2 | wc -l";
|
|
607
|
+
}
|
|
608
|
+
else if (platform === "darwin") {
|
|
609
|
+
command = "netstat -an | grep ESTABLISHED | wc -l";
|
|
610
|
+
}
|
|
611
|
+
else if (platform === "win32") {
|
|
612
|
+
command = 'netstat -an | find /c "ESTABLISHED"';
|
|
613
|
+
}
|
|
614
|
+
if (command) {
|
|
615
|
+
const { stdout } = await execAsync(command);
|
|
616
|
+
return parseInt(stdout.trim()) || 0;
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
catch (_error) {
|
|
620
|
+
logger.debug("Could not get network connections:", _error);
|
|
621
|
+
}
|
|
622
|
+
return 0;
|
|
623
|
+
}
|
|
624
|
+
/**
|
|
625
|
+
* Get top processes by CPU or memory usage
|
|
626
|
+
*/
|
|
627
|
+
async getTopProcesses(sortBy = "cpu", limit = 10) {
|
|
628
|
+
const platform = process.platform;
|
|
629
|
+
const processes = [];
|
|
630
|
+
try {
|
|
631
|
+
if (platform === "linux" || platform === "darwin") {
|
|
632
|
+
const sortFlag = sortBy === "cpu" ? "-pcpu" : "-pmem";
|
|
633
|
+
const { stdout } = await execAsync(`ps aux --sort=${sortFlag} | head -${limit + 1} | tail -${limit}`);
|
|
634
|
+
const lines = stdout.trim().split("\n");
|
|
635
|
+
for (const line of lines) {
|
|
636
|
+
const parts = line.trim().split(/\s+/);
|
|
637
|
+
if (parts.length >= 11) {
|
|
638
|
+
processes.push({
|
|
639
|
+
pid: parseInt(parts[1]),
|
|
640
|
+
cpu: parseFloat(parts[2]),
|
|
641
|
+
memory: parseFloat(parts[3]),
|
|
642
|
+
name: parts[10],
|
|
643
|
+
uptime: 0, // Would need additional parsing
|
|
644
|
+
});
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
else if (platform === "win32") {
|
|
649
|
+
await execAsync("wmic process get ProcessId,Name,PageFileUsage,UserModeTime /format:csv");
|
|
650
|
+
// Parse Windows output
|
|
651
|
+
// Implementation would be more complex
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
catch (_error) {
|
|
655
|
+
logger.debug("Could not get process list:", _error);
|
|
656
|
+
}
|
|
657
|
+
return processes;
|
|
658
|
+
}
|
|
659
|
+
/**
|
|
660
|
+
* Get CPU usage history
|
|
661
|
+
*/
|
|
662
|
+
getCPUHistory() {
|
|
663
|
+
return [...this.cpuUsageHistory];
|
|
664
|
+
}
|
|
665
|
+
/**
|
|
666
|
+
* Monitor system health continuously
|
|
667
|
+
*/
|
|
668
|
+
async startMonitoring(interval = 5000, callback) {
|
|
669
|
+
// Initial reading
|
|
670
|
+
await this.getSystemHealth();
|
|
671
|
+
return setInterval(async () => {
|
|
672
|
+
try {
|
|
673
|
+
const health = await this.getSystemHealth();
|
|
674
|
+
if (callback) {
|
|
675
|
+
callback(health);
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
catch (_error) {
|
|
679
|
+
logger.error("Error monitoring system health:", _error);
|
|
680
|
+
}
|
|
681
|
+
}, interval);
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
// Singleton instance
|
|
685
|
+
let systemMonitor = null;
|
|
686
|
+
export function getSystemMonitor() {
|
|
687
|
+
if (!systemMonitor) {
|
|
688
|
+
systemMonitor = new SystemMonitor();
|
|
689
|
+
}
|
|
690
|
+
return systemMonitor;
|
|
691
|
+
}
|
|
692
|
+
export default SystemMonitor;
|
|
693
|
+
//# sourceMappingURL=systemMonitor.js.map
|