@remcp/runtime 0.2.213 → 0.2.214
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
CHANGED
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
spawnDetached,
|
|
26
26
|
unavailable,
|
|
27
27
|
} from './common.mjs';
|
|
28
|
+
import { parseWindowsServiceStatus } from './windows-scm-status.mjs';
|
|
28
29
|
|
|
29
30
|
|
|
30
31
|
function durationSpec(value) {
|
|
@@ -52,6 +53,16 @@ export async function serviceTool(args) {
|
|
|
52
53
|
}
|
|
53
54
|
const safe = escapePowerShellSingle(name);
|
|
54
55
|
if (action === 'status') {
|
|
56
|
+
const scm = process.env.SystemRoot
|
|
57
|
+
? path.join(process.env.SystemRoot, 'System32', 'sc.exe') : 'sc.exe';
|
|
58
|
+
const [state, config] = await Promise.all([
|
|
59
|
+
runFile(scm, ['query', name], { label: 'Windows SCM state', timeout: 8_000, allowFailure: true }),
|
|
60
|
+
runFile(scm, ['qc', name], { label: 'Windows SCM config', timeout: 8_000, allowFailure: true }),
|
|
61
|
+
]);
|
|
62
|
+
if (state.code === 0 && config.code === 0) {
|
|
63
|
+
const parsed = parseWindowsServiceStatus(state.stdout, config.stdout, name);
|
|
64
|
+
if (parsed) return text(JSON.stringify(parsed));
|
|
65
|
+
}
|
|
55
66
|
const { stdout } = await runPowerShell(`Get-Service -Name '${safe}' | Select-Object Name,DisplayName,Status,StartType | ConvertTo-Json -Compress`, { label: 'service status' });
|
|
56
67
|
return text(stdout.trim());
|
|
57
68
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// SCM is much cheaper than loading Windows PowerShell on a pressured VM.
|
|
2
|
+
// Keep the existing Get-Service JSON contract and fall back when output is
|
|
3
|
+
// localized or cannot be parsed reliably.
|
|
4
|
+
export function parseWindowsServiceStatus(query, config, requestedName) {
|
|
5
|
+
const value = (source, key) => String(source).match(new RegExp(
|
|
6
|
+
'^\\s*' + key + '\\s*:\\s*(.*?)\\r?$', 'mi'))?.[1]?.trim();
|
|
7
|
+
const queryName = value(query, 'SERVICE_NAME');
|
|
8
|
+
const configName = value(config, 'SERVICE_NAME');
|
|
9
|
+
const state = Number(value(query, 'STATE')?.match(/^(\d+)(?:\s|$)/)?.[1]);
|
|
10
|
+
const start = Number(value(config, 'START_TYPE')?.match(/^(\d+)(?:\s|$)/)?.[1]);
|
|
11
|
+
const displayName = value(config, 'DISPLAY_NAME');
|
|
12
|
+
if (!requestedName || !queryName || !configName ||
|
|
13
|
+
queryName.toLowerCase() !== requestedName.toLowerCase() ||
|
|
14
|
+
configName.toLowerCase() !== queryName.toLowerCase() ||
|
|
15
|
+
!Number.isInteger(state) || state < 1 || state > 7 ||
|
|
16
|
+
!Number.isInteger(start) || start < 0 || start > 4 ||
|
|
17
|
+
!displayName || displayName.includes('\uFFFD')) return null;
|
|
18
|
+
return { Name: queryName, DisplayName: displayName, Status: state, StartType: start };
|
|
19
|
+
}
|