const STALE_SESSION_PATTERN = /^omo-agents-(\d+)$/ function isProcessAlive(pid: number): boolean { try { process.kill(pid, 0) return true } catch (error) { const err = error as NodeJS.ErrnoException return err?.code === "EPERM" } } async function listOmoAgentSessionsViaTmux(tmux: string): Promise { const { spawn } = await import("./spawn-process") const proc = spawn([tmux, "list-sessions", "-F", "#{session_name}"], { stdout: "pipe", stderr: "pipe", }) const [stdout, , exitCode] = await Promise.all([ new Response(proc.stdout).text(), new Response(proc.stderr).text(), proc.exited, ]) if (exitCode !== 0) { return [] } return stdout .split("\n") .map((line) => line.trim()) .filter((name) => STALE_SESSION_PATTERN.test(name)) } export type SweepDeps = { isInsideTmux: () => boolean getTmuxPath: () => Promise listCandidateSessions: (tmux: string) => Promise killSession: (sessionName: string) => Promise processAlive: (pid: number) => boolean currentPid: number log: (message: string, payload?: unknown) => void } async function buildRuntimeDeps(): Promise { const [{ log }, { isInsideTmux }, { getTmuxPath }, { killTmuxSessionIfExists }] = await Promise.all([ import("../../logger"), import("./environment"), import("../../../tools/interactive-bash/tmux-path-resolver"), import("./session-kill"), ]) return { isInsideTmux, getTmuxPath, listCandidateSessions: listOmoAgentSessionsViaTmux, killSession: killTmuxSessionIfExists, processAlive: isProcessAlive, currentPid: process.pid, log, } } export async function sweepStaleOmoAgentSessionsWith(deps: SweepDeps): Promise { if (!deps.isInsideTmux()) { return 0 } const tmux = await deps.getTmuxPath() if (!tmux) { return 0 } const candidateSessions = await deps.listCandidateSessions(tmux) let killedCount = 0 for (const sessionName of candidateSessions) { const pidMatch = sessionName.match(STALE_SESSION_PATTERN) if (!pidMatch) continue const pid = Number.parseInt(pidMatch[1], 10) if (!Number.isFinite(pid)) continue if (pid === deps.currentPid) continue if (deps.processAlive(pid)) continue deps.log("[sweepStaleOmoAgentSessions] killing stale session", { sessionName, deadPid: pid }) const killed = await deps.killSession(sessionName) if (killed) { killedCount += 1 } } return killedCount } export async function sweepStaleOmoAgentSessions(): Promise { const deps = await buildRuntimeDeps() return sweepStaleOmoAgentSessionsWith(deps) }