Tool to send cross-session opencode messages, including as request-response pattern
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

implement proc sensor

rektide cb8301f9 2bdd3800

+109
+109
src/sensor/proc.ts
··· 1 + import { readdir, readFile } from "node:fs/promises"; 2 + import { join } from "node:path"; 3 + 4 + export interface Instance { 5 + pid: number; 6 + port?: number; 7 + cwd?: string; 8 + type: "proc"; 9 + } 10 + 11 + interface ProcInfo { 12 + pid: number; 13 + cmdline: string[]; 14 + cwd?: string; 15 + } 16 + 17 + async function readProcCmdline(pid: number): Promise<string[]> { 18 + try { 19 + const cmdlinePath = join("/proc", pid.toString(), "cmdline"); 20 + const content = await readFile(cmdlinePath, "utf-8"); 21 + return content.split("\0").filter((arg) => arg.length > 0); 22 + } catch { 23 + return []; 24 + } 25 + } 26 + 27 + async function readProcCwd(pid: number): Promise<string | undefined> { 28 + try { 29 + const cwdPath = join("/proc", pid.toString(), "cwd"); 30 + const linkTarget = await readFile(cwdPath, "utf-8"); 31 + return linkTarget.trim(); 32 + } catch { 33 + return undefined; 34 + } 35 + } 36 + 37 + async function getOpenCodeProcesses(): Promise<ProcInfo[]> { 38 + const processes: ProcInfo[] = []; 39 + 40 + try { 41 + const procDir = "/proc"; 42 + const entries = await readdir(procDir, { withFileTypes: true }); 43 + 44 + for (const entry of entries) { 45 + if (!entry.isDirectory() || !/^\d+$/.test(entry.name)) { 46 + continue; 47 + } 48 + 49 + const pid = parseInt(entry.name, 10); 50 + const cmdline = await readProcCmdline(pid); 51 + 52 + if (cmdline.length === 0) { 53 + continue; 54 + } 55 + 56 + const cmd = cmdline[0].toLowerCase(); 57 + if ( 58 + !cmd.includes("opencode") && 59 + !cmd.includes("bun") && 60 + !cmd.includes("node") 61 + ) { 62 + continue; 63 + } 64 + 65 + const args = cmdline.slice(1).join(" ").toLowerCase(); 66 + if (!args.includes("opencode")) { 67 + continue; 68 + } 69 + 70 + const cwd = await readProcCwd(pid); 71 + processes.push({ pid, cmdline, cwd }); 72 + } 73 + } catch (error) { 74 + return []; 75 + } 76 + 77 + return processes; 78 + } 79 + 80 + function extractPortFromArgs(args: string[]): number | undefined { 81 + for (let i = 0; i < args.length; i++) { 82 + if (args[i] === "--port" && i + 1 < args.length) { 83 + const port = parseInt(args[i + 1], 10); 84 + if (!isNaN(port)) { 85 + return port; 86 + } 87 + } 88 + } 89 + return undefined; 90 + } 91 + 92 + export class ProcSensor { 93 + async discover(): Promise<Instance[]> { 94 + const processes = await getOpenCodeProcesses(); 95 + const instances: Instance[] = []; 96 + 97 + for (const proc of processes) { 98 + const port = extractPortFromArgs(proc.cmdline); 99 + instances.push({ 100 + pid: proc.pid, 101 + port, 102 + cwd: proc.cwd, 103 + type: "proc", 104 + }); 105 + } 106 + 107 + return instances; 108 + } 109 + }