@remcp/runtime 0.2.220 → 0.2.222
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/package.json +1 -1
- package/src/tools/cpu-telemetry.mjs +11 -0
- package/src/tools/system-telemetry.mjs +31 -4
- package/src/tools/system.mjs +21 -14
package/package.json
CHANGED
|
@@ -34,6 +34,17 @@ export function cpuPerCoreUtilizationRatios(before, after) {
|
|
|
34
34
|
return ratios.every(value => value !== null) ? ratios : null;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
// Windows diagnostics spawn PowerShell probes. Measure host CPU first, or the
|
|
38
|
+
// diagnostics themselves can appear as a false 100% CPU spike on small VMs.
|
|
39
|
+
export async function scheduleCpuSampleAndProbes(platform, sampleCpu, startProbes) {
|
|
40
|
+
if (platform === 'win32') {
|
|
41
|
+
const cpus = await sampleCpu();
|
|
42
|
+
return { cpus, probes: startProbes() };
|
|
43
|
+
}
|
|
44
|
+
const probes = startProbes();
|
|
45
|
+
return { cpus: await sampleCpu(), probes };
|
|
46
|
+
}
|
|
47
|
+
|
|
37
48
|
export function cpuFrequencyMHz(cores) {
|
|
38
49
|
if (!Array.isArray(cores) || !cores.length) return null;
|
|
39
50
|
const speeds = cores.map(core => core?.speed).filter(speed => Number.isFinite(speed) && speed > 0 && speed <= 100000);
|
|
@@ -75,6 +75,25 @@ export function parseWindowsNetworkCounters(input, activeNames = null) {
|
|
|
75
75
|
return [...found.values()];
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
+
// netsh exposes cumulative interface bytes even on Windows hosts where the
|
|
79
|
+
// NetAdapterStatistics PowerShell provider returns no entries. Match columns
|
|
80
|
+
// rather than localized header words; reject unsafe aliases and fake rates.
|
|
81
|
+
export function parseWindowsNetshCounters(input, activeNames = null) {
|
|
82
|
+
const found = new Map();
|
|
83
|
+
for (const line of String(input).split(/\r?\n/).slice(0, 130)) {
|
|
84
|
+
const match = line.match(/^\s*\d{1,10}\s+1\s+(\d{1,16})\s+(\d{1,16})\s+(.+?)\s*$/u);
|
|
85
|
+
if (!match) continue;
|
|
86
|
+
const name = match[3];
|
|
87
|
+
if (!/^[\p{L}\p{N} _().:#-]{1,64}$/u.test(name) ||
|
|
88
|
+
(activeNames && !activeNames.has(name))) continue;
|
|
89
|
+
const rx = Number(match[1]), tx = Number(match[2]);
|
|
90
|
+
if (!numeric(rx) || !numeric(tx)) continue;
|
|
91
|
+
found.set(name, { name, rx, tx });
|
|
92
|
+
if (found.size >= 24) break;
|
|
93
|
+
}
|
|
94
|
+
return [...found.values()];
|
|
95
|
+
}
|
|
96
|
+
|
|
78
97
|
export function calculateNetworkRates(current, previous, elapsedSeconds) {
|
|
79
98
|
if (!Array.isArray(current) || !Array.isArray(previous) || !Number.isFinite(elapsedSeconds) ||
|
|
80
99
|
elapsedSeconds < 1 || elapsedSeconds > 300) return null;
|
|
@@ -114,13 +133,21 @@ async function readNetworkCounters() {
|
|
|
114
133
|
return parseDarwinNetworkCounters(stdout, active);
|
|
115
134
|
}
|
|
116
135
|
if (process.platform === 'win32') {
|
|
117
|
-
const script = 'Get-NetAdapterStatistics | Select-Object Name,ReceivedBytes,SentBytes | ConvertTo-Json -Compress';
|
|
118
|
-
const { stdout } = await run('powershell.exe', ['-NoProfile', '-NonInteractive', '-Command', script],
|
|
119
|
-
{ windowsHide: true, timeout: 5000, maxBuffer: 128 * 1024 });
|
|
120
136
|
const active = new Set(Object.entries(os.networkInterfaces())
|
|
121
137
|
.filter(([, addresses]) => addresses?.some(address => !address.internal))
|
|
122
138
|
.map(([name]) => name));
|
|
123
|
-
|
|
139
|
+
try {
|
|
140
|
+
const { stdout } = await run('netsh', ['interface', 'ipv4', 'show', 'subinterfaces'],
|
|
141
|
+
{ windowsHide: true, timeout: 2500, maxBuffer: 128 * 1024 });
|
|
142
|
+
const counters = parseWindowsNetshCounters(stdout, active);
|
|
143
|
+
if (counters.length) return counters;
|
|
144
|
+
} catch { /* Fall through to the existing adapter provider. */ }
|
|
145
|
+
try {
|
|
146
|
+
const script = 'Get-NetAdapterStatistics | Select-Object Name,ReceivedBytes,SentBytes | ConvertTo-Json -Compress';
|
|
147
|
+
const { stdout } = await run('powershell.exe', ['-NoProfile', '-NonInteractive', '-Command', script],
|
|
148
|
+
{ windowsHide: true, timeout: 5000, maxBuffer: 128 * 1024 });
|
|
149
|
+
return parseWindowsNetworkCounters(stdout, active);
|
|
150
|
+
} catch { return []; }
|
|
124
151
|
}
|
|
125
152
|
return [];
|
|
126
153
|
}
|
package/src/tools/system.mjs
CHANGED
|
@@ -6,7 +6,7 @@ import { statfs } from 'node:fs/promises';
|
|
|
6
6
|
import { promisify } from 'node:util';
|
|
7
7
|
import { runtimeConfig } from '../config.mjs';
|
|
8
8
|
import { clampInteger, fail, requireInteger, text } from '../util.mjs';
|
|
9
|
-
import { cpuUtilizationRatio, cpuFrequencyMHz, cpuPerCoreUtilizationRatios } from './cpu-telemetry.mjs';
|
|
9
|
+
import { cpuUtilizationRatio, cpuFrequencyMHz, cpuPerCoreUtilizationRatios, scheduleCpuSampleAndProbes } from './cpu-telemetry.mjs';
|
|
10
10
|
import { diskVolumes, networkRates, thermalReadings } from './system-telemetry.mjs';
|
|
11
11
|
import { readDarwinMemoryPressure } from './darwin-memory-pressure.mjs';
|
|
12
12
|
|
|
@@ -63,14 +63,21 @@ export async function getSystemInfoTool() {
|
|
|
63
63
|
const totalMem = os.totalmem();
|
|
64
64
|
const freeMem = os.freemem();
|
|
65
65
|
const load = os.loadavg();
|
|
66
|
-
//
|
|
67
|
-
//
|
|
68
|
-
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
66
|
+
// On Windows, the PowerShell sensor probes can saturate short CPU samples.
|
|
67
|
+
// Measure CPU before launching them; keep other platforms' parallel probes.
|
|
68
|
+
// Load average is queue length, never a percentage.
|
|
69
|
+
const { cpus: sampledCpus, probes } = await scheduleCpuSampleAndProbes(
|
|
70
|
+
process.platform,
|
|
71
|
+
() => new Promise(resolve => setTimeout(() => resolve(os.cpus()), 140)),
|
|
72
|
+
() => ({
|
|
73
|
+
diskPromise: diskUsage(),
|
|
74
|
+
volumesPromise: diskVolumes(),
|
|
75
|
+
thermalPromise: thermalReadings(),
|
|
76
|
+
networkPromise: networkRates(),
|
|
77
|
+
memoryPressurePromise: process.platform === 'darwin'
|
|
78
|
+
? readDarwinMemoryPressure() : Promise.resolve(null),
|
|
79
|
+
}),
|
|
80
|
+
);
|
|
74
81
|
const utilizationRatio = cpuUtilizationRatio(cpus, sampledCpus);
|
|
75
82
|
const frequencyMHz = cpuFrequencyMHz(sampledCpus);
|
|
76
83
|
return text(JSON.stringify({
|
|
@@ -95,12 +102,12 @@ export async function getSystemInfoTool() {
|
|
|
95
102
|
freeBytes: freeMem,
|
|
96
103
|
usedRatio: totalMem ? Number(((totalMem - freeMem) / totalMem).toFixed(3)) : 0,
|
|
97
104
|
usedMethod: 'os.freemem-physical-occupancy',
|
|
98
|
-
...(await memoryPressurePromise),
|
|
105
|
+
...(await probes.memoryPressurePromise),
|
|
99
106
|
},
|
|
100
|
-
disk: await diskPromise,
|
|
101
|
-
volumes: await volumesPromise,
|
|
102
|
-
temperatures: await thermalPromise,
|
|
103
|
-
network: await networkPromise,
|
|
107
|
+
disk: await probes.diskPromise,
|
|
108
|
+
volumes: await probes.volumesPromise,
|
|
109
|
+
temperatures: await probes.thermalPromise,
|
|
110
|
+
network: await probes.networkPromise,
|
|
104
111
|
home: os.homedir(),
|
|
105
112
|
tempDir: os.tmpdir(),
|
|
106
113
|
runtimeName: runtimeConfig.name,
|