import { spawnSync } from "node:child_process"; type EnvMap = Record; export type VitestProcessStats = { otherVitestRootCount: number; otherVitestWorkerCount: number; otherVitestCpuPercent: number; }; type PsResult = { status: number | null; stdout: string; }; type DetectVitestProcessStatsOptions = { platform?: NodeJS.Platform; selfPid?: number; runPs?: () => PsResult; }; const EMPTY_VITEST_PROCESS_STATS: VitestProcessStats = { otherVitestRootCount: 0, otherVitestWorkerCount: 0, otherVitestCpuPercent: 0, }; const BOOLEAN_TRUE_VALUES = new Set(["1", "true"]); function isExplicitlyEnabled(value: string | undefined): boolean { const normalized = value?.trim().toLowerCase(); return normalized ? BOOLEAN_TRUE_VALUES.has(normalized) : false; } function isVitestWorkerArgs(args: string): boolean { return args.includes("/vitest/dist/workers/") || args.includes("\\vitest\\dist\\workers\\"); } function isVitestRootArgs(args: string): boolean { return ( args.includes("node_modules/.bin/vitest") || /\bvitest(?:\.(?:m?js|cmd|exe))?\b/u.test(args) || args.includes("scripts/test-projects.mjs") || args.includes("scripts/run-vitest.mjs") ); } function normalizeCpu(rawCpu: string): number { const parsed = Number.parseFloat(rawCpu); return Number.isFinite(parsed) && parsed > 0 ? parsed : 0; } export function parseVitestProcessStats( psOutput: string, selfPid: number = process.pid, ): VitestProcessStats { const stats = { ...EMPTY_VITEST_PROCESS_STATS }; for (const line of psOutput.split("\n")) { const trimmed = line.trim(); if (trimmed.length === 0) { continue; } const match = /^(\d+)\s+([0-9.]+)\s+(.*)$/u.exec(trimmed); if (!match) { continue; } const [, rawPid, rawCpu, args] = match; const pid = Number.parseInt(rawPid, 10); if (!Number.isFinite(pid) || pid === selfPid) { continue; } if (!isVitestWorkerArgs(args) && !isVitestRootArgs(args)) { continue; } stats.otherVitestCpuPercent += normalizeCpu(rawCpu); if (isVitestWorkerArgs(args)) { stats.otherVitestWorkerCount += 1; } else { stats.otherVitestRootCount += 1; } } stats.otherVitestCpuPercent = Number.parseFloat(stats.otherVitestCpuPercent.toFixed(1)); return stats; } export function detectVitestProcessStats( env: EnvMap = process.env, options: DetectVitestProcessStatsOptions = {}, ): VitestProcessStats { const platform = options.platform ?? process.platform; if (platform === "win32") { return { ...EMPTY_VITEST_PROCESS_STATS }; } if (isExplicitlyEnabled(env.OPENCLAW_VITEST_DISABLE_SYSTEM_THROTTLE)) { return { ...EMPTY_VITEST_PROCESS_STATS }; } const result = options.runPs?.() ?? spawnSync("ps", ["-xao", "pid=,pcpu=,args="], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], }); if (result.status === 0 && typeof result.stdout === "string" && result.stdout.length > 0) { return parseVitestProcessStats(result.stdout, options.selfPid ?? process.pid); } return { ...EMPTY_VITEST_PROCESS_STATS }; } export function shouldPrintVitestThrottle(env: EnvMap = process.env): boolean { const normalized = env.OPENCLAW_VITEST_PRINT_SYSTEM_THROTTLE?.trim().toLowerCase(); return normalized ? BOOLEAN_TRUE_VALUES.has(normalized) : false; }