import { execFileSync } from 'child_process'; const CPU_THRESHOLD_SECONDS = 3600; // 1 hour export function parsePowerShellOutput(csv, now = new Date()) { const lines = csv.trim().split(/\r?\n/); if (lines.length < 2) return []; const header = lines[0].split(','); const idxPid = header.indexOf('Id'); const idxName = header.indexOf('ProcessName'); const idxCpu = header.indexOf('CPU'); const idxStart = header.indexOf('StartTime'); const procs = []; for (let i = 1; i < lines.length; i++) { const cells = lines[i].split(','); if (cells.length < 4) continue; const startTime = new Date(cells[idxStart]); const ageMinutes = Math.max(0, Math.floor((now - startTime) / 60000)); procs.push({ pid: parseInt(cells[idxPid], 10), name: cells[idxName], cpuSeconds: parseFloat(cells[idxCpu]), ageMinutes, }); } return procs; } export function queryRunningProcesses() { // PowerShell command: get heavy processes, output as CSV without quotes const psCmd = "Get-Process | Where-Object {$_.CPU -gt 3600} | Select-Object Id,ProcessName,CPU,StartTime | ConvertTo-Csv -NoTypeInformation | ForEach-Object {$_ -replace '\"',''}"; try { const out = execFileSync('powershell.exe', [ '-NoProfile', '-NonInteractive', '-Command', psCmd, ], { encoding: 'utf-8', timeout: 5000 }); return parsePowerShellOutput(out, new Date()); } catch (e) { return []; } } export function computeSystemHealthBlock(procs) { const heavy = (procs || []) .filter(p => p.cpuSeconds > CPU_THRESHOLD_SECONDS) .sort((a, b) => b.cpuSeconds - a.cpuSeconds) .slice(0, 3); if (heavy.length === 0) { return `## System Health\n\nДолго работающих процессов нет (порог CPU > 1ч).\n`; } const rows = heavy.map(p => { const hours = (p.cpuSeconds / 3600).toFixed(2); const ageHours = (p.ageMinutes / 60).toFixed(1); return `| ${p.pid} | ${p.name} | ${hours}ч | ${ageHours}ч |`; }).join('\n'); return `## System Health\n\nТоп-3 процессов с CPU > 1ч:\n\n| PID | Имя | CPU-время | Возраст |\n|---|---|---|---|\n${rows}\n\n⚠️ Проверь, не «осиротевшие» ли это процессы от завершённых Claude-сессий.\n`; }