"use strict"; const { createExecOnSessionApi } = require("./systemManager/execOnSession.cjs"); const { createTmuxOpsApi } = require("./systemManager/tmuxOps.cjs"); const { createDockerOpsApi } = require("./systemManager/dockerOps.cjs"); const { createGpuOpsApi } = require("./systemManager/gpuOps.cjs"); const { createPortOpsApi } = require("./systemManager/portOps.cjs"); const { createServiceOpsApi } = require("./systemManager/serviceOps.cjs"); const { PROCESS_LIST_PS_COMMAND, buildStopProcessPsCommand, CAPABILITY_PROBE_PS_COMMAND, } = require("./systemManager/windowsPowerShell.cjs"); const CAPABILITY_SCRIPT_POSIX = [ "exec sh -c ", "'", 'printf "%s\\n" "__NC_OS__=$(uname -s)"; ', 'command -v tmux >/dev/null 2>&1 && printf "%s\\n" __NC_TMUX__=1; ', 'command -v docker >/dev/null 2>&1 && printf "%s\\n" __NC_DOCKER__=1; ', 'command -v nvidia-smi >/dev/null 2>&1 && printf "%s\\n" __NC_NVIDIA_SMI__=1; ', 'command -v npu-smi >/dev/null 2>&1 && printf "%s\\n" __NC_NPU_SMI__=1; ', 'command -v ss >/dev/null 2>&1 && printf "%s\\n" __NC_SS__=1; ', 'command -v netstat >/dev/null 2>&1 && printf "%s\\n" __NC_NETSTAT__=1; ', 'command -v lsof >/dev/null 2>&1 && printf "%s\\n" __NC_LSOF__=1; ', 'command -v systemctl >/dev/null 2>&1 && printf "%s\\n" __NC_SYSTEMCTL__=1', "'", ].join(""); const PROCESS_LIST_SCRIPT_POSIX = [ "exec sh -c ", "'", "ps -eo pid= -o ppid= -o user= -o stat= -o pcpu= -o pmem= -o rss= -o vsz= -o etime= -o args= 2>/dev/null || top -b -n 1 2>/dev/null || ps ww 2>/dev/null || ps 2>/dev/null", "'", ].join(""); const PROCESS_LIST_MAX_BUFFER = 64 * 1024 * 1024; function parseCapabilities(stdout, isLocal, localPlatform) { const text = stdout || ""; let targetOs = "unknown"; if (isLocal) { if (localPlatform === "linux") targetOs = "linux"; else if (localPlatform === "darwin") targetOs = "darwin"; else if (localPlatform === "win32") targetOs = "win32"; } else { const osMatch = text.match(/__NC_OS__=([^\r\n]+)/); const uname = (osMatch?.[1] || "").trim().toLowerCase(); if (uname.includes("linux")) targetOs = "linux"; else if (uname.includes("darwin")) targetOs = "darwin"; else if (uname.includes("windows") || uname.includes("mingw")) targetOs = "win32"; } // Line-anchored markers only — avoid matching probe-script source echoed by // noisy shells / vendor CLIs that reprint the command text. const hasFlag = (name) => new RegExp(`(?:^|\\r?\\n)${name}=1(?:\\r?\\n|$)`).test(text); const hasTmux = hasFlag("__NC_TMUX__"); const hasDocker = hasFlag("__NC_DOCKER__"); const hasNvidiaSmi = hasFlag("__NC_NVIDIA_SMI__"); const hasNpuSmi = hasFlag("__NC_NPU_SMI__"); const hasSs = hasFlag("__NC_SS__"); const hasNetstat = hasFlag("__NC_NETSTAT__"); const hasLsof = hasFlag("__NC_LSOF__"); const hasSystemctl = hasFlag("__NC_SYSTEMCTL__"); return { targetOs, hasTmux, hasDocker, hasNvidiaSmi, hasNpuSmi, hasSs, hasNetstat, hasLsof, hasSystemctl, probedAt: Date.now(), }; } function parseProcessLines(stdout) { const processes = []; for (const line of (stdout || "").split("\n")) { const trimmed = line.trim(); if (!trimmed) continue; const m = trimmed.match(/^(\d+)\s+(\d+)\s+(\S+)\s+(\S+)\s+([\d.]+)\s+([\d.]+)\s+(\d+)\s+(\d+)\s+(\S+)\s+(.+)$/); if (m) { processes.push({ pid: Number(m[1]), ppid: Number(m[2]), user: m[3], stat: m[4], cpuPercent: Number(m[5]), memPercent: Number(m[6]), rssKb: Number(m[7]), vszKb: Number(m[8]), elapsed: m[9], command: m[10], }); continue; } const busyBoxTopMatch = trimmed.match( /^(\d+)\s+(\d+)\s+(\S+)\s+(\S+)\s+(\d+(?:\.\d+)?[mgtpezy]?)\s+([\d.]+)%?\s+(?:\d+\s+)?([\d.]+)%?\s+(.+)$/i, ); if (busyBoxTopMatch) { const suffix = busyBoxTopMatch[5].slice(-1).toLowerCase(); const multipliers = { m: 1024, g: 1024 ** 2, t: 1024 ** 3, p: 1024 ** 4, e: 1024 ** 5, z: 1024 ** 6, y: 1024 ** 7 }; const multiplier = multipliers[suffix] || 1; processes.push({ pid: Number(busyBoxTopMatch[1]), ppid: Number(busyBoxTopMatch[2]), user: busyBoxTopMatch[3], stat: busyBoxTopMatch[4], cpuPercent: Number(busyBoxTopMatch[7]), memPercent: Number(busyBoxTopMatch[6]), rssKb: 0, vszKb: Math.round(Number.parseFloat(busyBoxTopMatch[5]) * multiplier), elapsed: "", command: busyBoxTopMatch[8], }); continue; } const busyBoxMatch = trimmed.match(/^(\d+)\s+(\S+)\s+(\d+(?:\.\d+)?[mgtpezy]?)\s+(\S+)\s+(.+)$/i); if (!busyBoxMatch) continue; const suffix = busyBoxMatch[3].slice(-1).toLowerCase(); const multipliers = { m: 1024, g: 1024 ** 2, t: 1024 ** 3, p: 1024 ** 4, e: 1024 ** 5, z: 1024 ** 6, y: 1024 ** 7 }; const multiplier = multipliers[suffix] || 1; processes.push({ pid: Number(busyBoxMatch[1]), ppid: 0, user: busyBoxMatch[2], stat: busyBoxMatch[4], cpuPercent: 0, memPercent: 0, rssKb: 0, vszKb: Math.round(Number.parseFloat(busyBoxMatch[3]) * multiplier), elapsed: "", command: busyBoxMatch[5], }); } return processes; } const ALLOWED_SIGNALS = new Set([ "TERM", "KILL", "STOP", "CONT", "HUP", "INT", "USR1", "USR2", "1", "2", "9", "15", "18", "19", ]); function buildProcessSignalCommand(pid, signal, nice) { if (nice !== undefined && nice !== null) { const n = Number(nice); if (!Number.isFinite(n) || n < -20 || n > 19) { return { error: "Invalid nice value" }; } return { command: `renice ${Math.trunc(n)} -p ${Number(pid)}` }; } const sig = String(signal || "TERM").toUpperCase(); if (!ALLOWED_SIGNALS.has(sig)) { return { error: "Invalid signal" }; } const numericPid = Number(pid); if (!Number.isFinite(numericPid) || numericPid <= 0) { return { error: "Invalid pid" }; } if (sig === "KILL" || sig === "9") { return { command: `kill -9 ${numericPid}` }; } if (sig === "TERM" || sig === "15") { return { command: `kill -15 ${numericPid}` }; } if (/^\d+$/.test(sig)) { return { command: `kill -${sig} ${numericPid}` }; } return { command: `kill -s ${sig} ${numericPid}` }; } function createSystemManagerBridge(deps) { const { getSessions, execOnEtSession, ensureMoshStatsConnection, process, } = deps; const execApi = createExecOnSessionApi({ sessions: { get: (id) => getSessions()?.get(id) }, execOnEtSession, ensureMoshStatsConnection, }); const { execOnSession, execOnLocalMachine, isLocalSession, getSession } = execApi; const tmuxOps = createTmuxOpsApi({ execOnSession }); const dockerOps = createDockerOpsApi({ execOnSession, getSession }); const gpuOps = createGpuOpsApi({ execOnSession, execOnLocalMachine, isLocalSession, process, }); const portOps = createPortOpsApi({ execOnSession, execOnLocalMachine, isLocalSession, process, }); const serviceOps = createServiceOpsApi({ execOnSession, getSession }); async function probeCapabilities(event, payload) { const sessionId = payload?.sessionId; if (!sessionId) return { success: false, error: "Missing sessionId" }; if (isLocalSession(sessionId)) { const platform = process.platform; let script = CAPABILITY_SCRIPT_POSIX; if (platform === "win32") { const result = await execOnLocalMachine( [ 'Write-Output "__NC_OS__=Windows"; ', "if (Get-Command tmux -ErrorAction SilentlyContinue) { Write-Output '__NC_TMUX__=1' }; ", "docker info 2>$null; if ($LASTEXITCODE -eq 0) { Write-Output '__NC_DOCKER__=1' }; ", "if (Get-Command nvidia-smi -ErrorAction SilentlyContinue) { Write-Output '__NC_NVIDIA_SMI__=1' }; ", "if (Get-Command npu-smi -ErrorAction SilentlyContinue) { Write-Output '__NC_NPU_SMI__=1' }; ", // Local Windows uses Get-NetTCPConnection; treat as netstat-capable for tab visibility. "Write-Output '__NC_NETSTAT__=1'; ", "if (Get-Command ss -ErrorAction SilentlyContinue) { Write-Output '__NC_SS__=1' }; ", "if (Get-Command lsof -ErrorAction SilentlyContinue) { Write-Output '__NC_LSOF__=1' }; ", "if (Get-Command systemctl -ErrorAction SilentlyContinue) { Write-Output '__NC_SYSTEMCTL__=1' }", ].join(""), 8000, ); if (!result.success) return { success: false, error: result.error || "Probe failed" }; return { success: true, capabilities: parseCapabilities(result.stdout, true, platform) }; } const result = await execOnLocalMachine( script.replace(/^exec sh -c '/, "").replace(/'$/, ""), 8000, ); if (!result.success) { const fallback = await execOnLocalMachine( [ "uname -s; ", "command -v tmux; ", "command -v docker >/dev/null 2>&1 && echo docker_ok; ", "command -v nvidia-smi >/dev/null 2>&1 && echo nvidia_ok; ", "command -v npu-smi >/dev/null 2>&1 && echo npu_ok; ", "command -v ss >/dev/null 2>&1 && echo ss_ok; ", "command -v netstat >/dev/null 2>&1 && echo netstat_ok; ", "command -v lsof >/dev/null 2>&1 && echo lsof_ok; ", "command -v systemctl >/dev/null 2>&1 && echo systemctl_ok", ].join(""), 8000, ); if (!fallback.success) return { success: false, error: fallback.error || "Probe failed" }; const text = fallback.stdout || ""; return { success: true, capabilities: { targetOs: platform === "linux" ? "linux" : platform === "darwin" ? "darwin" : "unknown", hasTmux: text.includes("tmux") && !text.includes("not found"), hasDocker: text.includes("docker_ok"), hasNvidiaSmi: text.includes("nvidia_ok"), hasNpuSmi: text.includes("npu_ok"), hasSs: text.includes("ss_ok"), hasNetstat: text.includes("netstat_ok"), hasLsof: text.includes("lsof_ok"), hasSystemctl: text.includes("systemctl_ok"), probedAt: Date.now(), }, }; } return { success: true, capabilities: parseCapabilities(result.stdout, true, platform) }; } const posixResult = await execOnSession(event, sessionId, CAPABILITY_SCRIPT_POSIX, 8000); if (posixResult.pending) return { success: false, pending: true }; console.log(`[ProbeCapabilities] POSIX result for session ${sessionId}: success=${posixResult.success}, code=${posixResult.code}, error=${JSON.stringify(posixResult.error||'').slice(0,120)}, stdoutSnippet=${JSON.stringify((posixResult.stdout||'').slice(0,200))}`); if (posixResult.success) { const parsed = parseCapabilities(posixResult.stdout, false, process.platform); console.log(`[ProbeCapabilities] POSIX parsed: targetOs=${parsed.targetOs}, hasDocker=${parsed.hasDocker}, hasNetstat=${parsed.hasNetstat}, hasSystemctl=${parsed.hasSystemctl}`); // If POSIX probe detected a real OS, trust it. if (parsed.targetOs !== "unknown") { return { success: true, capabilities: parsed }; } } // POSIX failed or got unknown OS — try Windows PowerShell probe. console.log(`[ProbeCapabilities] POSIX gave unknown OS, falling back to PowerShell probe.`); const psResult = await execOnSession(event, sessionId, CAPABILITY_PROBE_PS_COMMAND, 10000); if (psResult.pending) return { success: false, pending: true }; console.log(`[ProbeCapabilities] PowerShell result: success=${psResult.success}, code=${psResult.code}, error=${JSON.stringify(psResult.error||'').slice(0,120)}, stdoutSnippet=${JSON.stringify((psResult.stdout||'').slice(0,200))}`); if (psResult.success) { const parsed = parseCapabilities(psResult.stdout, false, process.platform); console.log(`[ProbeCapabilities] PowerShell parsed: targetOs=${parsed.targetOs}, hasDocker=${parsed.hasDocker}, hasNetstat=${parsed.hasNetstat}, hasSystemctl=${parsed.hasSystemctl}`); if (parsed.targetOs !== "unknown") { return { success: true, capabilities: parsed }; } } // Neither probe worked — return whatever POSIX had (or an unknown record). if (!posixResult.success) return { success: false, error: posixResult.error || "Probe failed" }; return { success: true, capabilities: parseCapabilities(posixResult.stdout, false, process.platform) }; } async function listProcesses(event, payload) { const sessionId = payload?.sessionId; if (!sessionId) return { success: false, error: "Missing sessionId" }; // Local Windows — already PowerShell. if (isLocalSession(sessionId) && process.platform === "win32") { const result = await execOnLocalMachine( PROCESS_LIST_PS_COMMAND, 10000, { maxBuffer: PROCESS_LIST_MAX_BUFFER }, ); if (!result.success) return { success: false, error: result.error }; try { const raw = JSON.parse(result.stdout || "[]"); const list = Array.isArray(raw) ? raw : [raw]; const processes = list.map((p) => ({ pid: Number(p.ProcessId), ppid: Number(p.ParentProcessId) || 0, user: "", stat: "R", cpuPercent: Number(p.CpuPercent) || 0, memPercent: Number(p.MemPercent) || 0, rssKb: Number(p.WorkingSetKb) || Math.round((Number(p.WorkingSetSize) || 0) / 1024), vszKb: 0, elapsed: String(p.Elapsed || ""), command: String(p.CommandLine || p.Name || ""), })); return { success: true, processes }; } catch { return { success: false, error: "Failed to parse process list" }; } } // POSIX first (Linux / macOS / BSD). const posixResult = await execOnSession(event, sessionId, PROCESS_LIST_SCRIPT_POSIX, 12000, { maxBuffer: PROCESS_LIST_MAX_BUFFER, }); if (posixResult.pending) return { success: false, pending: true }; const posixOk = posixResult.success; const posixProcesses = posixOk ? parseProcessLines(posixResult.stdout) : []; // If POSIX gave zero processes, try Windows PowerShell (Windows OpenSSH host). if (!posixOk || posixProcesses.length === 0) { const psResult = await execOnSession(event, sessionId, PROCESS_LIST_PS_COMMAND, 12000, { maxBuffer: PROCESS_LIST_MAX_BUFFER, }); if (psResult.pending) return { success: false, pending: true }; if (psResult.success) { try { const raw = JSON.parse(psResult.stdout || "[]"); const list = Array.isArray(raw) ? raw : raw ? [raw] : []; if (list.length > 0) { const processes = list.map((p) => ({ pid: Number(p.ProcessId), ppid: Number(p.ParentProcessId) || 0, user: "", stat: "R", cpuPercent: Number(p.CpuPercent) || 0, memPercent: Number(p.MemPercent) || 0, rssKb: Number(p.WorkingSetKb) || 0, vszKb: 0, elapsed: String(p.Elapsed || ""), command: String(p.CommandLine || p.Name || ""), })); return { success: true, processes }; } } catch { // PowerShell parse failed — fall back to POSIX result or original error. } } } if (!posixOk) return { success: false, error: posixResult.error || "Failed to list processes" }; return { success: true, processes: posixProcesses }; } async function signalProcess(event, payload) { const { sessionId, pid, signal = "TERM", nice } = payload || {}; if (!sessionId || !pid) return { success: false, error: "Missing sessionId or pid" }; const numericPid = Number(pid); if (!Number.isFinite(numericPid) || numericPid <= 0) { return { success: false, error: "Invalid pid" }; } // Local Windows has no POSIX kill; map only TERM/KILL onto Stop-Process. if (isLocalSession(sessionId) && process.platform === "win32") { if (nice !== undefined && nice !== null) { return { success: false, error: "renice is not supported on Windows" }; } const sig = String(signal || "TERM").toUpperCase(); if (!(sig === "TERM" || sig === "15" || sig === "KILL" || sig === "9")) { return { success: false, error: `signal ${sig} is not supported on Windows` }; } const force = sig === "KILL" || sig === "9"; const ps = force ? `Stop-Process -Id ${Math.trunc(numericPid)} -Force -ErrorAction Stop` : `Stop-Process -Id ${Math.trunc(numericPid)} -ErrorAction Stop`; const result = await execOnLocalMachine(ps, 5000); if (!result.success) return { success: false, error: result.error || "Stop-Process failed" }; if (typeof result.code === "number" && result.code !== 0) { return { success: false, error: (result.stderr || result.error || `Stop-Process exited with code ${result.code}`).trim(), code: result.code, }; } return { success: true, code: result.code }; } const built = buildProcessSignalCommand(pid, signal, nice); if (built.error) return { success: false, error: built.error }; const result = await execOnSession(event, sessionId, `exec sh -c ${JSON.stringify(built.command)}`, 5000); if (result.pending) return { success: false, pending: true, error: result.error }; // POSIX worked. if (result.success && (result.code === 0 || result.code == null)) { return { success: true, code: result.code ?? 0 }; } // POSIX failed — try Windows PowerShell Stop-Process. const sig = String(signal || "TERM").toUpperCase(); const force = sig === "KILL" || sig === "9"; const psCmd = buildStopProcessPsCommand(pid, force); if (psCmd) { const psResult = await execOnSession(event, sessionId, psCmd, 8000); if (psResult.pending) return { success: false, pending: true, error: psResult.error }; if (psResult.success && (psResult.code === 0 || psResult.code == null)) { return { success: true, code: psResult.code ?? 0 }; } } if (!result.success) return { success: false, error: result.error }; if (typeof result.code === "number" && result.code !== 0) { return { success: false, error: (result.stderr || result.error || `kill exited with code ${result.code}`).trim(), code: result.code, }; } return { success: true, code: result.code }; } async function setupOsc7Tracking(event, payload) { const sessionId = payload?.sessionId; const command = payload?.command; if (!sessionId || typeof command !== "string" || !command.trim()) { return { success: false, error: "Missing sessionId or command" }; } const result = await execOnSession(event, sessionId, command, 10000); if (result.pending) return { success: false, pending: true, error: result.error }; if (!result.success) return { success: false, error: result.error || "Directory tracking setup failed" }; if (typeof result.code === "number" && result.code !== 0) { const error = String(result.stderr || result.error || `Directory tracking setup failed with exit code ${result.code}`).trim(); return { success: false, stdout: result.stdout || "", stderr: result.stderr || "", code: result.code, error, }; } return { success: true, stdout: result.stdout || "", stderr: result.stderr || "", code: result.code ?? 0, }; } async function listTmuxSessions(event, payload) { const sessionId = typeof payload === "string" ? payload : payload?.sessionId; if (!sessionId) return { success: false, error: "Missing sessionId" }; return tmuxOps.listSessions(event, sessionId); } async function createTmuxSession(event, payload) { return tmuxOps.createSession(event, payload); } async function listTmuxWindows(event, payload) { return tmuxOps.listWindows(event, payload); } async function listTmuxPanes(event, payload) { return tmuxOps.listPanes(event, payload); } async function listTmuxClients(event, payload) { return tmuxOps.listClients(event, payload); } async function tmuxAction(event, payload) { const result = await tmuxOps.tmuxAction(event, payload); if (result.success === false && result.error) { return { success: false, error: result.error || result.stderr }; } if (result.success === false) { return { success: false, error: result.stderr || "tmux command failed" }; } return { success: true }; } async function listDockerContainers(event, payload) { const sessionId = payload?.sessionId; if (!sessionId) return { success: false, error: "Missing sessionId" }; return dockerOps.listContainers(event, sessionId); } async function listDockerImages(event, payload) { const sessionId = payload?.sessionId; if (!sessionId) return { success: false, error: "Missing sessionId" }; return dockerOps.listImages(event, sessionId); } async function dockerStats(event, payload) { return dockerOps.getStats(event, payload); } async function dockerInspect(event, payload) { return dockerOps.inspectContainer(event, payload); } async function dockerImageInspect(event, payload) { return dockerOps.inspectImage(event, payload); } async function dockerAction(event, payload) { const result = await dockerOps.containerAction(event, payload); if (result.success === false) { return { success: false, error: result.error || result.stderr || "docker command failed" }; } return { success: true }; } async function dockerImageAction(event, payload) { const result = await dockerOps.imageAction(event, payload); if (result.success === false) { return { success: false, error: result.error || result.stderr || "docker command failed" }; } return { success: true, output: result.stdout }; } async function listAccelerators(event, payload) { const sessionId = payload?.sessionId; if (!sessionId) return { success: false, error: "Missing sessionId" }; return gpuOps.listAccelerators(event, sessionId); } async function listListeningPorts(event, payload) { const sessionId = payload?.sessionId; if (!sessionId) return { success: false, error: "Missing sessionId" }; return portOps.listListeningPorts(event, sessionId); } async function listSystemServices(event, payload) { const sessionId = payload?.sessionId; if (!sessionId) return { success: false, error: "Missing sessionId" }; return serviceOps.listServices(event, sessionId); } async function systemServiceAction(event, payload) { return serviceOps.serviceAction(event, payload); } function registerWorkerHandle(ipcMain, terminalWorkerManager, channel) { ipcMain.handle(channel, (event, payload) => terminalWorkerManager.request(channel, payload, { webContentsId: event?.sender?.id, })); } function registerHandlers(ipcMain, options = {}) { const terminalWorkerManager = options.terminalWorkerManager || null; if (terminalWorkerManager) { [ "netcatty:system:probeCapabilities", "netcatty:system:listProcesses", "netcatty:system:signalProcess", "netcatty:system:setupOsc7Tracking", "netcatty:system:listTmuxSessions", "netcatty:system:createTmuxSession", "netcatty:system:listTmuxWindows", "netcatty:system:listTmuxPanes", "netcatty:system:listTmuxClients", "netcatty:system:tmuxAction", "netcatty:system:listDockerContainers", "netcatty:system:listDockerImages", "netcatty:system:dockerStats", "netcatty:system:dockerInspect", "netcatty:system:dockerImageInspect", "netcatty:system:dockerAction", "netcatty:system:dockerImageAction", "netcatty:system:listAccelerators", "netcatty:system:listListeningPorts", "netcatty:system:listSystemServices", "netcatty:system:systemServiceAction", ].forEach((channel) => registerWorkerHandle(ipcMain, terminalWorkerManager, channel)); return; } ipcMain.handle("netcatty:system:probeCapabilities", probeCapabilities); ipcMain.handle("netcatty:system:listProcesses", listProcesses); ipcMain.handle("netcatty:system:signalProcess", signalProcess); ipcMain.handle("netcatty:system:setupOsc7Tracking", setupOsc7Tracking); ipcMain.handle("netcatty:system:listTmuxSessions", listTmuxSessions); ipcMain.handle("netcatty:system:createTmuxSession", createTmuxSession); ipcMain.handle("netcatty:system:listTmuxWindows", listTmuxWindows); ipcMain.handle("netcatty:system:listTmuxPanes", listTmuxPanes); ipcMain.handle("netcatty:system:listTmuxClients", listTmuxClients); ipcMain.handle("netcatty:system:tmuxAction", tmuxAction); ipcMain.handle("netcatty:system:listDockerContainers", listDockerContainers); ipcMain.handle("netcatty:system:listDockerImages", listDockerImages); ipcMain.handle("netcatty:system:dockerStats", dockerStats); ipcMain.handle("netcatty:system:dockerInspect", dockerInspect); ipcMain.handle("netcatty:system:dockerImageInspect", dockerImageInspect); ipcMain.handle("netcatty:system:dockerAction", dockerAction); ipcMain.handle("netcatty:system:dockerImageAction", dockerImageAction); ipcMain.handle("netcatty:system:listAccelerators", listAccelerators); ipcMain.handle("netcatty:system:listListeningPorts", listListeningPorts); ipcMain.handle("netcatty:system:listSystemServices", listSystemServices); ipcMain.handle("netcatty:system:systemServiceAction", systemServiceAction); } return { registerHandlers, probeCapabilities, listProcesses, signalProcess, setupOsc7Tracking }; } module.exports = { createSystemManagerBridge };