import { spawnSync } from 'child_process'; import * as fs from 'fs'; export type DaemonOwnershipStatus = 'owned' | 'not-owned' | 'not-running' | 'unknown'; function sleepSync(milliseconds: number): void { Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, milliseconds); } function getProcessCommandLine(pid: number): string | null { if (process.platform === 'linux') { for (let attempt = 0; attempt < 3; attempt++) { try { // /proc cmdline uses null separators between arguments. const commandLine = fs .readFileSync(`/proc/${pid}/cmdline`, 'utf8') .replace(/\0/g, ' ') .trim(); if (commandLine) { return commandLine; } } catch { return null; } sleepSync(25); } return null; } if (process.platform === 'darwin') { try { const result = spawnSync('ps', ['-p', String(pid), '-o', 'command='], { encoding: 'utf8', }); if (result.error || result.status !== 0) { return null; } return result.stdout.trim(); } catch { return null; } } if (process.platform === 'win32') { const command = `(Get-CimInstance Win32_Process -Filter "ProcessId = ${pid}" | Select-Object -ExpandProperty CommandLine)`; const shells = ['powershell.exe', 'powershell', 'pwsh.exe', 'pwsh']; for (const shell of shells) { try { const result = spawnSync(shell, ['-NoProfile', '-Command', command], { encoding: 'utf8', }); if (result.error) { continue; } if (result.status !== 0) { return null; } return result.stdout.trim(); } catch { // Try next shell candidate } } return null; } return null; } export function verifyProcessOwnership( pid: number, ownershipMatcher: (commandLine: string) => boolean ): DaemonOwnershipStatus { try { process.kill(pid, 0); } catch (err) { const error = err as NodeJS.ErrnoException; if (error.code === 'ESRCH') { return 'not-running'; } return 'unknown'; } const commandLine = getProcessCommandLine(pid); if (!commandLine) { return 'unknown'; } return ownershipMatcher(commandLine) ? 'owned' : 'not-owned'; } export function verifyDaemonOwnership(pid: number): DaemonOwnershipStatus { return verifyProcessOwnership( pid, (commandLine) => commandLine.includes('--ccs-daemon') && commandLine.includes('cursor-daemon-entry') ); }