CoolFace
Datasetpublic

basant307/AI_Governance_Project

sourceHugging Faceapache-2.0updated 2mo agoView on Hugging Face
0likes48downloads
process-utils.ts220 linesDownload Raw Back to ide
1/**2 * @license3 * Copyright 2025 Google LLC4 * SPDX-License-Identifier: Apache-2.05 */6 7import { exec, execFile } from 'node:child_process';8import { promisify } from 'node:util';9import os from 'node:os';10import path from 'node:path';11 12const execAsync = promisify(exec);13const execFileAsync = promisify(execFile);14 15const MAX_TRAVERSAL_DEPTH = 32;16 17async function getProcessInfo(pid: number): Promise<{18  parentPid: number;19  name: string;20  command: string;21}> {22  // Only used for Unix systems (macOS and Linux)23  try {24    const command = `ps -o ppid=,command= -p ${pid}`;25    const { stdout } = await execAsync(command);26    const trimmedStdout = stdout.trim();27    if (!trimmedStdout) {28      return { parentPid: 0, name: '', command: '' };29    }30    const parts = trimmedStdout.split(/\s+/);31    const ppidString = parts[0];32    const parentPid = parseInt(ppidString, 10);33    const fullCommand = trimmedStdout.substring(ppidString.length).trim();34    const processName = path.basename(fullCommand.split(' ')[0]);35    return {36      parentPid: isNaN(parentPid) ? 1 : parentPid,37      name: processName,38      command: fullCommand,39    };40  } catch (_e) {41    return { parentPid: 0, name: '', command: '' };42  }43}44/**45 * Finds the IDE process info on Unix-like systems.46 *47 * The strategy is to find the shell process that spawned the CLI, and then48 * find that shell's parent process (the IDE). To get the true IDE process,49 * we traverse one level higher to get the grandparent.50 *51 * @returns A promise that resolves to the PID and command of the IDE process.52 */53async function getIdeProcessInfoForUnix(): Promise<{54  pid: number;55  command: string;56}> {57  const shells = ['zsh', 'bash', 'sh', 'tcsh', 'csh', 'ksh', 'fish', 'dash'];58  let currentPid = process.pid;59 60  for (let i = 0; i < MAX_TRAVERSAL_DEPTH; i++) {61    try {62      const { parentPid, name } = await getProcessInfo(currentPid);63 64      const isShell = shells.some((shell) => name === shell);65      if (isShell) {66        // The direct parent of the shell is often a utility process (e.g. VS67        // Code's `ptyhost` process). To get the true IDE process, we need to68        // traverse one level higher to get the grandparent.69        let idePid = parentPid;70        try {71          const { parentPid: grandParentPid } = await getProcessInfo(parentPid);72          if (grandParentPid > 1) {73            idePid = grandParentPid;74          }75        } catch {76          // Ignore if getting grandparent fails, we'll just use the parent pid.77        }78        const { command: ideCommand } = await getProcessInfo(idePid);79        return { pid: idePid, command: ideCommand };80      }81 82      if (parentPid <= 1) {83        break; // Reached the root84      }85      currentPid = parentPid;86    } catch (_e) {87      // Process in chain died88      break;89    }90  }91 92  const { command } = await getProcessInfo(currentPid);93  return { pid: currentPid, command };94}95 96interface ProcessInfo {97  pid: number;98  parentPid: number;99  name: string;100  command: string;101}102 103interface RawProcessInfo {104  ProcessId?: number;105  ParentProcessId?: number;106  Name?: string;107  CommandLine?: string;108}109 110/**111 * Fetches the entire process table on Windows.112 */113async function getProcessTableWindows(): Promise<Map<number, ProcessInfo>> {114  const processMap = new Map<number, ProcessInfo>();115  try {116    const powershellCommand =117      'Get-CimInstance Win32_Process | Select-Object ProcessId,ParentProcessId,Name,CommandLine | ConvertTo-Json -Compress';118    const { stdout } = await execFileAsync(119      'powershell',120      ['-NoProfile', '-NonInteractive', '-Command', powershellCommand],121      { maxBuffer: 10 * 1024 * 1024 },122    );123 124    if (!stdout.trim()) {125      return processMap;126    }127 128    let processes: RawProcessInfo | RawProcessInfo[];129    try {130      processes = JSON.parse(stdout);131    } catch (_e) {132      return processMap;133    }134 135    if (!Array.isArray(processes)) {136      processes = [processes];137    }138 139    for (const p of processes) {140      if (p && typeof p.ProcessId === 'number') {141        processMap.set(p.ProcessId, {142          pid: p.ProcessId,143          parentPid: p.ParentProcessId || 0,144          name: p.Name || '',145          command: p.CommandLine || '',146        });147      }148    }149  } catch (_e) {150    // Fallback or error handling if PowerShell fails151  }152  return processMap;153}154 155async function getIdeProcessInfoForWindows(): Promise<{156  pid: number;157  command: string;158}> {159  // Fetch the entire process table in one go.160  const processMap = await getProcessTableWindows();161 162  const myPid = process.pid;163  const myProc = processMap.get(myPid);164 165  if (!myProc) {166    // Fallback: return current process info if snapshot fails167    return { pid: myPid, command: '' };168  }169 170  // Perform tree traversal in memory171  const ancestors: ProcessInfo[] = [];172  let curr: ProcessInfo | undefined = myProc;173 174  for (let i = 0; i < MAX_TRAVERSAL_DEPTH && curr; i++) {175    ancestors.push(curr);176 177    if (curr.parentPid === 0 || !processMap.has(curr.parentPid)) {178      // Parent process not in map, stop traversal179      break;180    }181    curr = processMap.get(curr.parentPid);182  }183 184  // Use heuristic: return the great-grandparent (ancestors[length-3])185  if (ancestors.length >= 3) {186    const target = ancestors[ancestors.length - 3];187    return { pid: target.pid, command: target.command };188  } else if (ancestors.length > 0) {189    const target = ancestors[ancestors.length - 1];190    return { pid: target.pid, command: target.command };191  }192 193  return { pid: myPid, command: myProc.command };194}195 196/**197 * Traverses up the process tree to find the process ID and command of the IDE.198 *199 * This function uses different strategies depending on the operating system200 * to identify the main application process (e.g., the main VS Code window201 * process).202 *203 * If the IDE process cannot be reliably identified, it will return the204 * top-level ancestor process ID and command as a fallback.205 *206 * @returns A promise that resolves to the PID and command of the IDE process.207 */208export async function getIdeProcessInfo(): Promise<{209  pid: number;210  command: string;211}> {212  const platform = os.platform();213 214  if (platform === 'win32') {215    return getIdeProcessInfoForWindows();216  }217 218  return getIdeProcessInfoForUnix();219}220 
basant307/AI_Governance_Project · CoolFace