UNPKG

porty-cli

Version:

A beautiful terminal UI for managing processes on network ports (Windows only)

134 lines (133 loc) 5.37 kB
import React, { useEffect, useState } from 'react'; import { Box, Text, useApp, useInput } from 'ink'; import { getProcessOnPort, killProcess } from '../utils/portDetector.js'; import { Logo } from './Logo.js'; export const KillMode = ({ port, force = false }) => { const { exit } = useApp(); const [loading, setLoading] = useState(true); const [process, setProcess] = useState(null); const [error, setError] = useState(null); const [waitingForConfirm, setWaitingForConfirm] = useState(false); const [killing, setKilling] = useState(false); const [result, setResult] = useState(null); useEffect(() => { const checkPort = async () => { try { const proc = await getProcessOnPort(port); setProcess(proc); setLoading(false); if (proc && force) { await performKill(proc.pid); } else if (proc) { setWaitingForConfirm(true); } else { setTimeout(() => exit(), 100); } } catch (err) { setError(err instanceof Error ? err.message : 'Unknown error'); setLoading(false); setTimeout(() => exit(), 100); } }; checkPort(); }, [port, force]); const performKill = async (pid) => { setKilling(true); setWaitingForConfirm(false); try { const success = await killProcess(pid); if (success) { setResult(`✓ Successfully killed process ${pid} on port ${port}`); } else { setResult(`✗ Failed to kill process ${pid}. Try running with elevated privileges.`); } } catch (err) { setResult(`✗ Error killing process: ${err instanceof Error ? err.message : 'Unknown error'}`); } finally { setKilling(false); setTimeout(() => exit(), 1000); } }; useInput((input, key) => { if (!waitingForConfirm) return; if (input === 'y' || input === 'Y') { if (process) { performKill(process.pid); } } else if (input === 'n' || input === 'N' || key.escape) { setResult('Kill cancelled'); setTimeout(() => exit(), 100); } }); if (loading) { return (React.createElement(Box, { flexDirection: "column" }, React.createElement(Logo, null), React.createElement(Box, null, React.createElement(Text, { color: "yellow" }, "Checking port ", port, "...")))); } if (error) { return (React.createElement(Box, { flexDirection: "column" }, React.createElement(Logo, null), React.createElement(Text, { color: "red" }, "Error checking port ", port, ":"), React.createElement(Text, { color: "red" }, error))); } if (!process) { return (React.createElement(Box, { flexDirection: "column" }, React.createElement(Logo, null), React.createElement(Box, null, React.createElement(Text, { color: "green" }, "Port ", port, " is already free!")))); } if (killing) { return (React.createElement(Box, { flexDirection: "column" }, React.createElement(Logo, null), React.createElement(Box, null, React.createElement(Text, { color: "yellow" }, "Killing process ", process.pid, "...")))); } if (result) { return (React.createElement(Box, { flexDirection: "column" }, React.createElement(Logo, null), React.createElement(Box, null, React.createElement(Text, { color: result.startsWith('✓') ? 'green' : result === 'Kill cancelled' ? 'yellow' : 'red' }, result)))); } if (waitingForConfirm) { return (React.createElement(Box, { flexDirection: "column" }, React.createElement(Logo, null), React.createElement(Text, { color: "cyan", bold: true }, "Process found on port ", port, ":"), React.createElement(Box, { marginTop: 1, flexDirection: "column" }, React.createElement(Text, null, React.createElement(Text, { color: "yellow" }, "PID: "), React.createElement(Text, null, process.pid)), React.createElement(Text, null, React.createElement(Text, { color: "yellow" }, "Process: "), React.createElement(Text, null, process.processName || 'Unknown')), React.createElement(Text, null, React.createElement(Text, { color: "yellow" }, "Command: "), React.createElement(Text, null, process.command || 'N/A'))), React.createElement(Box, { marginTop: 1 }, React.createElement(Text, { color: "red", bold: true }, "Kill this process? (y/n):")))); } return null; };