( commandExecutor: CommandExecutor, currentPid: number, )
| 202 | } |
| 203 | |
| 204 | async function sampleMcpPeerProcesses( |
| 205 | commandExecutor: CommandExecutor, |
| 206 | currentPid: number, |
| 207 | ): Promise<PeerProcessSample> { |
| 208 | try { |
| 209 | const result = await commandExecutor( |
| 210 | ['ps', '-axo', 'pid=,etime=,rss=,command='], |
| 211 | 'Sample MCP lifecycle peer processes', |
| 212 | false, |
| 213 | ); |
| 214 | if (!result.success) { |
| 215 | return { count: null, peers: [] }; |
| 216 | } |
| 217 | |
| 218 | const matched = result.output |
| 219 | .split('\n') |
| 220 | .map((line) => line.trim()) |
| 221 | .filter(Boolean) |
| 222 | .map((line) => { |
| 223 | const match = line.match(/^(\d+)\s+(\S+)\s+(\d+)\s+(.+)$/); |
| 224 | if (!match) { |
| 225 | return null; |
| 226 | } |
| 227 | const [, pidRaw, elapsedRaw, rssRaw, command] = match; |
| 228 | const ageSeconds = parseElapsedSeconds(elapsedRaw); |
| 229 | return { |
| 230 | pid: Number(pidRaw), |
| 231 | ageSeconds, |
| 232 | rssKb: Number(rssRaw), |
| 233 | command, |
| 234 | }; |
| 235 | }) |
| 236 | .filter( |
| 237 | (entry): entry is { pid: number; ageSeconds: number; rssKb: number; command: string } => { |
| 238 | return ( |
| 239 | entry !== null && |
| 240 | Number.isFinite(entry.pid) && |
| 241 | Number.isFinite(entry.ageSeconds) && |
| 242 | Number.isFinite(entry.rssKb) && |
| 243 | isLikelyMcpProcessCommand(entry.command) |
| 244 | ); |
| 245 | }, |
| 246 | ); |
| 247 | |
| 248 | const peers = matched |
| 249 | .filter((entry) => entry.pid !== currentPid) |
| 250 | .map(({ pid, ageSeconds, rssKb }) => ({ pid, ageSeconds, rssKb })) |
| 251 | .sort((left, right) => right.ageSeconds - left.ageSeconds || right.rssKb - left.rssKb) |
| 252 | .slice(0, 5); |
| 253 | |
| 254 | return { |
| 255 | count: matched.length, |
| 256 | peers, |
| 257 | }; |
| 258 | } catch { |
| 259 | return { count: null, peers: [] }; |
| 260 | } |
| 261 | } |
no test coverage detected